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*25614Seric static char	SccsId[] = "@(#)srvrsmtp.c	5.17 (Berkeley) 12/17/85	(no SMTP)";
1923122Seric # endif not lint
205181Seric # else SMTP
214556Seric 
2223122Seric # ifndef lint
23*25614Seric static char	SccsId[] = "@(#)srvrsmtp.c	5.17 (Berkeley) 12/17/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;
1088544Seric 	char inp[MAXLINE];
10924981Seric 	char cmdbuf[100];
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();
12724971Seric 	if (RealHostName != NULL)
12825050Seric 	{
12925050Seric 		CurHostName = RealHostName;
13025050Seric 		setproctitle("srvrsmtp %s", CurHostName);
13125050Seric 	}
13225050Seric 	else
13325050Seric 	{
13425050Seric 		/* this must be us!! */
13525050Seric 		CurHostName = MyHostName;
13625050Seric 	}
13716153Seric 	expand("\001e", inp, &inp[sizeof inp], CurEnv);
13810708Seric 	message("220", inp);
13924943Seric 	SmtpPhase = "startup";
1404549Seric 	for (;;)
1414549Seric 	{
14212612Seric 		/* arrange for backout */
14312612Seric 		if (setjmp(TopFrame) > 0 && InChild)
14412612Seric 			finis();
14512612Seric 		QuickAbort = FALSE;
14612612Seric 		HoldErrs = FALSE;
14712612Seric 
1487356Seric 		/* setup for the read */
1496907Seric 		CurEnv->e_to = NULL;
1504577Seric 		Errors = 0;
1517275Seric 		(void) fflush(stdout);
1527356Seric 
1537356Seric 		/* read the input line */
1547685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1557356Seric 
1567685Seric 		/* handle errors */
1577356Seric 		if (p == NULL)
1587356Seric 		{
1594549Seric 			/* end of file, just die */
16025050Seric 			message("421", "%s Lost input channel to %s",
16125050Seric 				MyHostName, CurHostName);
1624549Seric 			finis();
1634549Seric 		}
1644549Seric 
1654549Seric 		/* clean up end of line */
1664558Seric 		fixcrlf(inp, TRUE);
1674549Seric 
1684713Seric 		/* echo command to transcript */
1699545Seric 		if (CurEnv->e_xfp != NULL)
1709545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1714713Seric 
1724549Seric 		/* break off command */
1734549Seric 		for (p = inp; isspace(*p); p++)
1744549Seric 			continue;
1754549Seric 		cmd = p;
17624981Seric 		for (cmd = cmdbuf; *p != '\0' && !isspace(*p); )
17724981Seric 			*cmd++ = *p++;
17824981Seric 		*cmd = '\0';
1794549Seric 
1804549Seric 		/* decode command */
1814549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1824549Seric 		{
18324984Seric 			if (sameword(c->cmdname, cmdbuf))
1844549Seric 				break;
1854549Seric 		}
1864549Seric 
1874549Seric 		/* process command */
1884549Seric 		switch (c->cmdcode)
1894549Seric 		{
1904976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
19124943Seric 			SmtpPhase = "HELO";
19225050Seric 			setproctitle("%s: %s", CurHostName, inp);
19325050Seric 			if (sameword(p, MyHostName))
19414877Seric 			{
19514877Seric 				/* connected to an echo server */
19614877Seric 				message("553", "%s I refuse to talk to myself",
19725050Seric 					MyHostName);
19814877Seric 				break;
19914877Seric 			}
20011146Seric 			if (RealHostName != NULL && !sameword(p, RealHostName))
20111146Seric 			{
20224981Seric 				char hostbuf[MAXNAME];
20311146Seric 
20424981Seric 				(void) sprintf(hostbuf, "%s (%s)", p, RealHostName);
20524981Seric 				define('s', newstr(hostbuf), CurEnv);
20611146Seric 			}
20711146Seric 			else
20811146Seric 				define('s', newstr(p), CurEnv);
2094997Seric 			message("250", "%s Hello %s, pleased to meet you",
21025050Seric 				MyHostName, p);
2114976Seric 			break;
2124976Seric 
2134549Seric 		  case CMDMAIL:		/* mail -- designate sender */
21424943Seric 			SmtpPhase = "MAIL";
21524943Seric 
21611151Seric 			/* force a sending host even if no HELO given */
21711151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
21811151Seric 				define('s', RealHostName, CurEnv);
21911151Seric 
2209314Seric 			/* check for validity of this command */
2214558Seric 			if (hasmail)
2224558Seric 			{
2234558Seric 				message("503", "Sender already specified");
2244558Seric 				break;
2254558Seric 			}
2269339Seric 			if (InChild)
2279339Seric 			{
2289339Seric 				syserr("Nested MAIL command");
2299339Seric 				exit(0);
2309339Seric 			}
2319339Seric 
2329339Seric 			/* fork a subprocess to process this command */
2339339Seric 			if (runinchild("SMTP-MAIL") > 0)
2349339Seric 				break;
2359339Seric 			initsys();
23625016Seric 			setproctitle("%s %s: %s", CurEnv->e_id,
23725050Seric 				CurHostName, inp);
2389339Seric 
2399339Seric 			/* child -- go do the processing */
2404549Seric 			p = skipword(p, "from");
2414549Seric 			if (p == NULL)
2424549Seric 				break;
2434549Seric 			setsender(p);
2444577Seric 			if (Errors == 0)
2454549Seric 			{
2464549Seric 				message("250", "Sender ok");
2474549Seric 				hasmail = TRUE;
2484549Seric 			}
2499339Seric 			else if (InChild)
2509339Seric 				finis();
2514549Seric 			break;
2524549Seric 
2534976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
25424943Seric 			SmtpPhase = "RCPT";
25525016Seric 			setproctitle("%s %s: %s", CurEnv->e_id,
25625050Seric 				CurHostName, inp);
25712612Seric 			if (setjmp(TopFrame) > 0)
25814785Seric 			{
25914785Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
26012612Seric 				break;
26114785Seric 			}
26212612Seric 			QuickAbort = TRUE;
2634549Seric 			p = skipword(p, "to");
2644549Seric 			if (p == NULL)
2654549Seric 				break;
26616140Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1, '\0');
26712612Seric 			if (a == NULL)
26812612Seric 				break;
26916886Seric 			a->q_flags |= QPRIMARY;
27012612Seric 			a = recipient(a, &CurEnv->e_sendqueue);
27112612Seric 			if (Errors != 0)
27212612Seric 				break;
27312612Seric 
27412612Seric 			/* no errors during parsing, but might be a duplicate */
27512612Seric 			CurEnv->e_to = p;
27612612Seric 			if (!bitset(QBADADDR, a->q_flags))
27712612Seric 				message("250", "Recipient ok");
27812612Seric 			else
2794549Seric 			{
28012612Seric 				/* punt -- should keep message in ADDRESS.... */
28112612Seric 				message("550", "Addressee unknown");
2824549Seric 			}
28312612Seric 			CurEnv->e_to = NULL;
2844549Seric 			break;
2854549Seric 
2864549Seric 		  case CMDDATA:		/* data -- text of mail */
28724943Seric 			SmtpPhase = "DATA";
2884976Seric 			if (!hasmail)
2894549Seric 			{
2904976Seric 				message("503", "Need MAIL command");
2914976Seric 				break;
2924549Seric 			}
29324943Seric 			else if (CurEnv->e_nrcpts <= 0)
2944549Seric 			{
2954976Seric 				message("503", "Need RCPT (recipient)");
2964976Seric 				break;
2974549Seric 			}
2984976Seric 
2994976Seric 			/* collect the text of the message */
30024943Seric 			SmtpPhase = "collect";
30125016Seric 			setproctitle("%s %s: %s", CurEnv->e_id,
30225050Seric 				CurHostName, inp);
3034976Seric 			collect(TRUE);
3044976Seric 			if (Errors != 0)
3054976Seric 				break;
3064976Seric 
3078238Seric 			/*
3088238Seric 			**  Arrange to send to everyone.
3098238Seric 			**	If sending to multiple people, mail back
3108238Seric 			**		errors rather than reporting directly.
3118238Seric 			**	In any case, don't mail back errors for
3128238Seric 			**		anything that has happened up to
3138238Seric 			**		now (the other end will do this).
31410197Seric 			**	Truncate our transcript -- the mail has gotten
31510197Seric 			**		to us successfully, and if we have
31610197Seric 			**		to mail this back, it will be easier
31710197Seric 			**		on the reader.
3188238Seric 			**	Then send to everyone.
3198238Seric 			**	Finally give a reply code.  If an error has
3208238Seric 			**		already been given, don't mail a
3218238Seric 			**		message back.
3229339Seric 			**	We goose error returns by clearing error bit.
3238238Seric 			*/
3248238Seric 
32524943Seric 			SmtpPhase = "delivery";
32624943Seric 			if (CurEnv->e_nrcpts != 1)
3279378Seric 			{
3289378Seric 				HoldErrs = TRUE;
32916886Seric 				ErrorMode = EM_MAIL;
3309378Seric 			}
3319339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
33210197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
3334976Seric 
3344976Seric 			/* send to all recipients */
33514877Seric 			sendall(CurEnv, SM_DEFAULT);
3366907Seric 			CurEnv->e_to = NULL;
3374976Seric 
33823516Seric 			/* save statistics */
33923516Seric 			markstats(CurEnv, (ADDRESS *) NULL);
34023516Seric 
3418238Seric 			/* issue success if appropriate and reset */
3428238Seric 			if (Errors == 0 || HoldErrs)
3439283Seric 				message("250", "Ok");
3448238Seric 			else
3459339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
3469339Seric 
3479339Seric 			/* if in a child, pop back to our parent */
3489339Seric 			if (InChild)
3499339Seric 				finis();
35024943Seric 
35124943Seric 			/* clean up a bit */
35224943Seric 			hasmail = 0;
35324943Seric 			dropenvelope(CurEnv);
35424943Seric 			CurEnv = newenvelope(CurEnv);
35524943Seric 			CurEnv->e_flags = BlankEnvelope.e_flags;
3564549Seric 			break;
3574549Seric 
3584549Seric 		  case CMDRSET:		/* rset -- reset state */
3594549Seric 			message("250", "Reset state");
3609339Seric 			if (InChild)
3619339Seric 				finis();
3629339Seric 			break;
3634549Seric 
3644549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
3659339Seric 			if (runinchild("SMTP-VRFY") > 0)
3669339Seric 				break;
36725050Seric 			setproctitle("%s: %s", CurHostName, inp);
3685003Seric 			vrfyqueue = NULL;
3697762Seric 			QuickAbort = TRUE;
3709619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
3717762Seric 			if (Errors != 0)
3729339Seric 			{
3739339Seric 				if (InChild)
3749339Seric 					finis();
3757762Seric 				break;
3769339Seric 			}
3775003Seric 			while (vrfyqueue != NULL)
3785003Seric 			{
3795003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3805003Seric 				char *code;
3815003Seric 
3827685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3835003Seric 					a = a->q_next;
3845003Seric 
3857685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3865003Seric 				{
3875003Seric 					if (a != NULL)
3885003Seric 						code = "250-";
3895003Seric 					else
3905003Seric 						code = "250";
3915003Seric 					if (vrfyqueue->q_fullname == NULL)
3925003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3935003Seric 					else
3945003Seric 						message(code, "%s <%s>",
3955003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3965003Seric 				}
3975003Seric 				else if (a == NULL)
3985003Seric 					message("554", "Self destructive alias loop");
3995003Seric 				vrfyqueue = a;
4005003Seric 			}
4019339Seric 			if (InChild)
4029339Seric 				finis();
4034549Seric 			break;
4044549Seric 
4054549Seric 		  case CMDHELP:		/* help -- give user info */
4064577Seric 			if (*p == '\0')
4074577Seric 				p = "SMTP";
4084577Seric 			help(p);
4094549Seric 			break;
4104549Seric 
4114549Seric 		  case CMDNOOP:		/* noop -- do nothing */
4124549Seric 			message("200", "OK");
4134549Seric 			break;
4144549Seric 
4154549Seric 		  case CMDQUIT:		/* quit -- leave mail */
41625050Seric 			message("221", "%s closing connection", MyHostName);
4179339Seric 			if (InChild)
4189339Seric 				ExitStat = EX_QUIT;
4194549Seric 			finis();
4204549Seric 
4218544Seric 		  case CMDVERB:		/* set verbose mode */
4228544Seric 			Verbose = TRUE;
42325025Seric 			SendMode = SM_DELIVER;
4248544Seric 			message("200", "Verbose mode");
4258544Seric 			break;
4268544Seric 
4279314Seric 		  case CMDONEX:		/* doing one transaction only */
4289378Seric 			OneXact = TRUE;
4299314Seric 			message("200", "Only one transaction");
4309314Seric 			break;
4319314Seric 
4325003Seric # ifdef DEBUG
4339339Seric 		  case CMDDBGQSHOW:	/* show queues */
4346907Seric 			printf("Send Queue=");
4356907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
4365003Seric 			break;
4377275Seric 
4387275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
4397676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
4407676Seric 			tTflag(p);
4417676Seric 			message("200", "Debug set");
4427275Seric 			break;
44324945Seric # endif DEBUG
4447275Seric 
44524945Seric # ifdef WIZ
4467282Seric 		  case CMDDBGKILL:	/* kill the parent */
4478544Seric 			if (!iswiz())
4488544Seric 				break;
4497282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
4507282Seric 				message("200", "Mother is dead");
4517282Seric 			else
4527282Seric 				message("500", "Can't kill Mom");
4537282Seric 			break;
4548544Seric 
4558544Seric 		  case CMDDBGWIZ:	/* become a wizard */
4568544Seric 			if (WizWord != NULL)
4578544Seric 			{
4588544Seric 				char seed[3];
4598544Seric 				extern char *crypt();
4608544Seric 
46123106Seric 				(void) strncpy(seed, WizWord, 2);
46215596Seric 				if (strcmp(WizWord, crypt(p, seed)) == 0)
4638544Seric 				{
46415596Seric 					IsWiz = TRUE;
46515596Seric 					message("200", "Please pass, oh mighty wizard");
4668544Seric 					break;
4678544Seric 				}
4688544Seric 			}
46915596Seric 			message("500", "You are no wizard!");
4708544Seric 			break;
4715003Seric 
47224945Seric # else WIZ
47324945Seric 		  case CMDDBGWIZ:	/* try to become a wizard */
47424945Seric 			message("500", "You wascal wabbit!  Wandering wizards won't win!");
47524945Seric 			break;
47624945Seric # endif WIZ
47724945Seric 
4784549Seric 		  case CMDERROR:	/* unknown command */
4794549Seric 			message("500", "Command unrecognized");
4804549Seric 			break;
4814549Seric 
4824549Seric 		  default:
4834549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4844549Seric 			break;
4854549Seric 		}
4864549Seric 	}
4874549Seric }
4884549Seric /*
4894549Seric **  SKIPWORD -- skip a fixed word.
4904549Seric **
4914549Seric **	Parameters:
4924549Seric **		p -- place to start looking.
4934549Seric **		w -- word to skip.
4944549Seric **
4954549Seric **	Returns:
4964549Seric **		p following w.
4974549Seric **		NULL on error.
4984549Seric **
4994549Seric **	Side Effects:
5004549Seric **		clobbers the p data area.
5014549Seric */
5024549Seric 
5034549Seric static char *
5044549Seric skipword(p, w)
5054549Seric 	register char *p;
5064549Seric 	char *w;
5074549Seric {
5084549Seric 	register char *q;
5094549Seric 	extern bool sameword();
5104549Seric 
5114549Seric 	/* find beginning of word */
5124549Seric 	while (isspace(*p))
5134549Seric 		p++;
5144549Seric 	q = p;
5154549Seric 
5164549Seric 	/* find end of word */
5174549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
5184549Seric 		p++;
5194549Seric 	while (isspace(*p))
5204549Seric 		*p++ = '\0';
5214549Seric 	if (*p != ':')
5224549Seric 	{
5234549Seric 	  syntax:
5244549Seric 		message("501", "Syntax error");
5254549Seric 		Errors++;
5264549Seric 		return (NULL);
5274549Seric 	}
5284549Seric 	*p++ = '\0';
5294549Seric 	while (isspace(*p))
5304549Seric 		p++;
5314549Seric 
5324549Seric 	/* see if the input word matches desired word */
5334549Seric 	if (!sameword(q, w))
5344549Seric 		goto syntax;
5354549Seric 
5364549Seric 	return (p);
5374549Seric }
5384577Seric /*
5394577Seric **  HELP -- implement the HELP command.
5404577Seric **
5414577Seric **	Parameters:
5424577Seric **		topic -- the topic we want help for.
5434577Seric **
5444577Seric **	Returns:
5454577Seric **		none.
5464577Seric **
5474577Seric **	Side Effects:
5484577Seric **		outputs the help file to message output.
5494577Seric */
5504577Seric 
5514577Seric help(topic)
5524577Seric 	char *topic;
5534577Seric {
5544577Seric 	register FILE *hf;
5554577Seric 	int len;
5564577Seric 	char buf[MAXLINE];
5574577Seric 	bool noinfo;
5584577Seric 
5598269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
5604577Seric 	{
5614577Seric 		/* no help */
56211931Seric 		errno = 0;
5634577Seric 		message("502", "HELP not implemented");
5644577Seric 		return;
5654577Seric 	}
5664577Seric 
5674577Seric 	len = strlen(topic);
5684577Seric 	makelower(topic);
5694577Seric 	noinfo = TRUE;
5704577Seric 
5714577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5724577Seric 	{
5734577Seric 		if (strncmp(buf, topic, len) == 0)
5744577Seric 		{
5754577Seric 			register char *p;
5764577Seric 
5774577Seric 			p = index(buf, '\t');
5784577Seric 			if (p == NULL)
5794577Seric 				p = buf;
5804577Seric 			else
5814577Seric 				p++;
5824577Seric 			fixcrlf(p, TRUE);
5834577Seric 			message("214-", p);
5844577Seric 			noinfo = FALSE;
5854577Seric 		}
5864577Seric 	}
5874577Seric 
5884577Seric 	if (noinfo)
5894577Seric 		message("504", "HELP topic unknown");
5904577Seric 	else
5914577Seric 		message("214", "End of HELP info");
5924628Seric 	(void) fclose(hf);
5934577Seric }
5948544Seric /*
5958544Seric **  ISWIZ -- tell us if we are a wizard
5968544Seric **
5978544Seric **	If not, print a nasty message.
5988544Seric **
5998544Seric **	Parameters:
6008544Seric **		none.
6018544Seric **
6028544Seric **	Returns:
6038544Seric **		TRUE if we are a wizard.
6048544Seric **		FALSE if we are not a wizard.
6058544Seric **
6068544Seric **	Side Effects:
6078544Seric **		Prints a 500 exit stat if we are not a wizard.
6088544Seric */
6095181Seric 
61024945Seric #ifdef WIZ
61119038Seric 
6128544Seric bool
6138544Seric iswiz()
6148544Seric {
6158544Seric 	if (!IsWiz)
6168544Seric 		message("500", "Mere mortals musn't mutter that mantra");
6178544Seric 	return (IsWiz);
6188544Seric }
61919038Seric 
62024945Seric #endif WIZ
6219339Seric /*
6229339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
6239339Seric **
6249339Seric **	Parameters:
6259339Seric **		label -- a string used in error messages
6269339Seric **
6279339Seric **	Returns:
6289339Seric **		zero in the child
6299339Seric **		one in the parent
6309339Seric **
6319339Seric **	Side Effects:
6329339Seric **		none.
6339339Seric */
6348544Seric 
6359339Seric runinchild(label)
6369339Seric 	char *label;
6379339Seric {
6389339Seric 	int childpid;
6399339Seric 
64016158Seric 	if (!OneXact)
6419339Seric 	{
64216158Seric 		childpid = dofork();
64316158Seric 		if (childpid < 0)
64416158Seric 		{
64516158Seric 			syserr("%s: cannot fork", label);
64616158Seric 			return (1);
64716158Seric 		}
64816158Seric 		if (childpid > 0)
64916158Seric 		{
65016158Seric 			auto int st;
6519339Seric 
65216158Seric 			/* parent -- wait for child to complete */
65316158Seric 			st = waitfor(childpid);
65416158Seric 			if (st == -1)
65516158Seric 				syserr("%s: lost child", label);
6569339Seric 
65716158Seric 			/* if we exited on a QUIT command, complete the process */
65816158Seric 			if (st == (EX_QUIT << 8))
65916158Seric 				finis();
6609339Seric 
66116158Seric 			return (1);
66216158Seric 		}
66316158Seric 		else
66416158Seric 		{
66516158Seric 			/* child */
66616158Seric 			InChild = TRUE;
66725050Seric 			QuickAbort = FALSE;
668*25614Seric 			clearenvelope(CurEnv, FALSE);
66916158Seric 		}
6709339Seric 	}
67115256Seric 
67216158Seric 	/* open alias database */
67316158Seric 	initaliases(AliasFile, FALSE);
67416158Seric 
67516158Seric 	return (0);
6769339Seric }
6779339Seric 
6785181Seric # endif SMTP
679