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*58308Seric static char sccsid[] = "@(#)srvrsmtp.c	6.18 (Berkeley) 02/28/93 (with SMTP)";
1433731Sbostic #else
15*58308Seric static char sccsid[] = "@(#)srvrsmtp.c	6.18 (Berkeley) 02/28/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 */
5158092Seric # define CMDEXPN	6	/* expn -- expand address */
529339Seric # define CMDNOOP	7	/* noop -- do nothing */
539339Seric # define CMDQUIT	8	/* quit -- close connection and die */
549339Seric # define CMDHELO	9	/* helo -- be polite */
5558092Seric # define CMDHELP	10	/* help -- give usage info */
5658092Seric /* non-standard commands */
5758092Seric # define CMDONEX	16	/* onex -- sending one transaction only */
5858092Seric # define CMDVERB	17	/* verb -- go into verbose mode */
5936230Skarels /* debugging-only commands, only enabled if SMTPDEBUG is defined */
6058092Seric # define CMDDBGQSHOW	24	/* showq -- show send queue */
6158092Seric # define CMDDBGDEBUG	25	/* debug -- set debug mode */
624549Seric 
634549Seric static struct cmd	CmdTab[] =
644549Seric {
654549Seric 	"mail",		CMDMAIL,
664976Seric 	"rcpt",		CMDRCPT,
674549Seric 	"data",		CMDDATA,
684549Seric 	"rset",		CMDRSET,
694549Seric 	"vrfy",		CMDVRFY,
7058092Seric 	"expn",		CMDEXPN,
714549Seric 	"help",		CMDHELP,
724549Seric 	"noop",		CMDNOOP,
734549Seric 	"quit",		CMDQUIT,
744976Seric 	"helo",		CMDHELO,
758544Seric 	"verb",		CMDVERB,
769314Seric 	"onex",		CMDONEX,
7736230Skarels 	/*
7836230Skarels 	 * remaining commands are here only
7936230Skarels 	 * to trap and log attempts to use them
8036230Skarels 	 */
819339Seric 	"showq",	CMDDBGQSHOW,
828544Seric 	"debug",	CMDDBGDEBUG,
834549Seric 	NULL,		CMDERROR,
844549Seric };
854549Seric 
869339Seric bool	InChild = FALSE;		/* true if running in a subprocess */
879378Seric bool	OneXact = FALSE;		/* one xaction only this run */
8811146Seric 
899339Seric #define EX_QUIT		22		/* special code for QUIT command */
908544Seric 
9155012Seric smtp(e)
9255012Seric 	register ENVELOPE *e;
934549Seric {
944549Seric 	register char *p;
958544Seric 	register struct cmd *c;
964549Seric 	char *cmd;
9746928Sbostic 	static char *skipword();
985003Seric 	auto ADDRESS *vrfyqueue;
9912612Seric 	ADDRESS *a;
10030448Seric 	char *sendinghost;
10158109Seric 	bool gotmail;			/* mail command received */
10258092Seric 	bool gothello;			/* helo command received */
10358092Seric 	bool vrfy;			/* set if this is a vrfy command */
1048544Seric 	char inp[MAXLINE];
10557232Seric 	char cmdbuf[MAXLINE];
1067124Seric 	extern char Version[];
10711151Seric 	extern char *macvalue();
10812612Seric 	extern ADDRESS *recipient();
10924943Seric 	extern ENVELOPE BlankEnvelope;
11024943Seric 	extern ENVELOPE *newenvelope();
1114549Seric 
11258109Seric 	gotmail = FALSE;
1137363Seric 	if (OutChannel != stdout)
1147363Seric 	{
1157363Seric 		/* arrange for debugging output to go to remote host */
1167363Seric 		(void) close(1);
1177363Seric 		(void) dup(fileno(OutChannel));
1187363Seric 	}
11955012Seric 	settime(e);
12057642Seric 	CurHostName = RealHostName;
12157642Seric 	setproctitle("srvrsmtp %s", CurHostName);
12258050Seric 	expand("\201e", inp, &inp[sizeof inp], e);
12358151Seric 	message("220 %s", inp);
12424943Seric 	SmtpPhase = "startup";
12530448Seric 	sendinghost = NULL;
12658082Seric 	gothello = FALSE;
1274549Seric 	for (;;)
1284549Seric 	{
12912612Seric 		/* arrange for backout */
13012612Seric 		if (setjmp(TopFrame) > 0 && InChild)
13112612Seric 			finis();
13212612Seric 		QuickAbort = FALSE;
13312612Seric 		HoldErrs = FALSE;
13451951Seric 		LogUsrErrs = FALSE;
13558092Seric 		e->e_flags &= ~EF_VRFYONLY;
13612612Seric 
1377356Seric 		/* setup for the read */
13855012Seric 		e->e_to = NULL;
1394577Seric 		Errors = 0;
1407275Seric 		(void) fflush(stdout);
1417356Seric 
1427356Seric 		/* read the input line */
14358109Seric 		p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand);
1447356Seric 
1457685Seric 		/* handle errors */
1467356Seric 		if (p == NULL)
1477356Seric 		{
1484549Seric 			/* end of file, just die */
14958151Seric 			message("421 %s Lost input channel from %s",
15025050Seric 				MyHostName, CurHostName);
15155464Seric #ifdef LOG
15258020Seric 			if (LogLevel > 1)
15355464Seric 				syslog(LOG_NOTICE, "lost input channel from %s",
15455464Seric 					CurHostName);
15555464Seric #endif
15658069Seric 			if (InChild)
15758069Seric 				ExitStat = EX_QUIT;
1584549Seric 			finis();
1594549Seric 		}
1604549Seric 
1614549Seric 		/* clean up end of line */
1624558Seric 		fixcrlf(inp, TRUE);
1634549Seric 
1644713Seric 		/* echo command to transcript */
16555012Seric 		if (e->e_xfp != NULL)
16655012Seric 			fprintf(e->e_xfp, "<<< %s\n", inp);
1674713Seric 
1684549Seric 		/* break off command */
16958050Seric 		for (p = inp; isascii(*p) && isspace(*p); p++)
1704549Seric 			continue;
17157232Seric 		cmd = cmdbuf;
17258050Seric 		while (*p != '\0' &&
17358050Seric 		       !(isascii(*p) && isspace(*p)) &&
17458050Seric 		       cmd < &cmdbuf[sizeof cmdbuf - 2])
17524981Seric 			*cmd++ = *p++;
17624981Seric 		*cmd = '\0';
1774549Seric 
17825691Seric 		/* throw away leading whitespace */
17958050Seric 		while (isascii(*p) && isspace(*p))
18025691Seric 			p++;
18125691Seric 
1824549Seric 		/* decode command */
1834549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1844549Seric 		{
18533725Sbostic 			if (!strcasecmp(c->cmdname, cmdbuf))
1864549Seric 				break;
1874549Seric 		}
1884549Seric 
18951954Seric 		/* reset errors */
19051954Seric 		errno = 0;
19151954Seric 
1924549Seric 		/* process command */
1934549Seric 		switch (c->cmdcode)
1944549Seric 		{
1954976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
19624943Seric 			SmtpPhase = "HELO";
19725050Seric 			setproctitle("%s: %s", CurHostName, inp);
19858109Seric 			if (strcasecmp(p, MyHostName) == 0)
19914877Seric 			{
20036230Skarels 				/*
20158109Seric 				**  Didn't know about alias or MX,
20258109Seric 				**  or connected to an echo server
20358109Seric 				*/
20458109Seric 
20558151Seric 				message("553 %s config error: mail loops back to myself",
20647570Seric 					MyHostName);
20714877Seric 				break;
20814877Seric 			}
209*58308Seric 			if (strcasecmp(p, RealHostName) != 0)
21011146Seric 			{
21124981Seric 				char hostbuf[MAXNAME];
21211146Seric 
21324981Seric 				(void) sprintf(hostbuf, "%s (%s)", p, RealHostName);
21430448Seric 				sendinghost = newstr(hostbuf);
21511146Seric 			}
21611146Seric 			else
21730448Seric 				sendinghost = newstr(p);
21858151Seric 			message("250 %s Hello %s, pleased to meet you",
21936230Skarels 				MyHostName, sendinghost);
22058082Seric 			gothello = TRUE;
2214976Seric 			break;
2224976Seric 
2234549Seric 		  case CMDMAIL:		/* mail -- designate sender */
22424943Seric 			SmtpPhase = "MAIL";
22524943Seric 
22611151Seric 			/* force a sending host even if no HELO given */
22758064Seric 			if (sendinghost == NULL && macvalue('s', e) == NULL)
22830448Seric 				sendinghost = RealHostName;
22911151Seric 
2309314Seric 			/* check for validity of this command */
23158082Seric 			if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags))
23258082Seric 			{
23358151Seric 				message("503 Polite people say HELO first");
23458082Seric 				break;
23558082Seric 			}
23658109Seric 			if (gotmail)
2374558Seric 			{
23858151Seric 				message("503 Sender already specified");
2394558Seric 				break;
2404558Seric 			}
2419339Seric 			if (InChild)
2429339Seric 			{
24336230Skarels 				errno = 0;
24458151Seric 				syserr("503 Nested MAIL command: MAIL %s", p);
24558069Seric 				finis();
2469339Seric 			}
24758082Seric 			if (!enoughspace())
24858082Seric 			{
24958151Seric 				message("452 Insufficient disk space; try again later");
25058082Seric 				break;
25158082Seric 			}
2529339Seric 
2539339Seric 			/* fork a subprocess to process this command */
25455012Seric 			if (runinchild("SMTP-MAIL", e) > 0)
2559339Seric 				break;
25658064Seric 			if (sendinghost != NULL)
25758064Seric 				define('s', sendinghost, e);
25855012Seric 			define('r', "SMTP", e);
25955012Seric 			initsys(e);
26057389Seric 			setproctitle("%s %s: %s", e->e_id, CurHostName, inp);
2619339Seric 
2629339Seric 			/* child -- go do the processing */
2634549Seric 			p = skipword(p, "from");
2644549Seric 			if (p == NULL)
2654549Seric 				break;
26657977Seric 			if (setjmp(TopFrame) > 0)
26758147Seric 			{
26858147Seric 				/* this failed -- undo work */
26958147Seric 				if (InChild)
27058147Seric 					finis();
27157977Seric 				break;
27258147Seric 			}
27357977Seric 			QuickAbort = TRUE;
27455012Seric 			setsender(p, e);
27558151Seric 			message("250 Sender ok");
27658147Seric 			gotmail = TRUE;
2774549Seric 			break;
2784549Seric 
2794976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
28024943Seric 			SmtpPhase = "RCPT";
28157389Seric 			setproctitle("%s %s: %s", e->e_id, CurHostName, inp);
28212612Seric 			if (setjmp(TopFrame) > 0)
28314785Seric 			{
28455012Seric 				e->e_flags &= ~EF_FATALERRS;
28512612Seric 				break;
28614785Seric 			}
28712612Seric 			QuickAbort = TRUE;
28851951Seric 			LogUsrErrs = TRUE;
28958093Seric 
29058093Seric 			/* optimization -- if queueing, don't expand aliases */
29158093Seric 			if (SendMode == SM_QUEUE)
29258093Seric 				e->e_flags |= EF_VRFYONLY;
29358093Seric 
2944549Seric 			p = skipword(p, "to");
2954549Seric 			if (p == NULL)
2964549Seric 				break;
29755012Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1, '\0', e);
29812612Seric 			if (a == NULL)
29912612Seric 				break;
30016886Seric 			a->q_flags |= QPRIMARY;
30155012Seric 			a = recipient(a, &e->e_sendqueue, e);
30212612Seric 			if (Errors != 0)
30312612Seric 				break;
30412612Seric 
30512612Seric 			/* no errors during parsing, but might be a duplicate */
30655012Seric 			e->e_to = p;
30712612Seric 			if (!bitset(QBADADDR, a->q_flags))
30858151Seric 				message("250 Recipient ok");
30912612Seric 			else
3104549Seric 			{
31112612Seric 				/* punt -- should keep message in ADDRESS.... */
31258151Seric 				message("550 Addressee unknown");
3134549Seric 			}
31455012Seric 			e->e_to = NULL;
3154549Seric 			break;
3164549Seric 
3174549Seric 		  case CMDDATA:		/* data -- text of mail */
31824943Seric 			SmtpPhase = "DATA";
31958109Seric 			if (!gotmail)
3204549Seric 			{
32158151Seric 				message("503 Need MAIL command");
3224976Seric 				break;
3234549Seric 			}
32455012Seric 			else if (e->e_nrcpts <= 0)
3254549Seric 			{
32658151Seric 				message("503 Need RCPT (recipient)");
3274976Seric 				break;
3284549Seric 			}
3294976Seric 
3304976Seric 			/* collect the text of the message */
33124943Seric 			SmtpPhase = "collect";
33257389Seric 			setproctitle("%s %s: %s", e->e_id, CurHostName, inp);
33355012Seric 			collect(TRUE, e);
3344976Seric 			if (Errors != 0)
3354976Seric 				break;
3364976Seric 
3378238Seric 			/*
3388238Seric 			**  Arrange to send to everyone.
3398238Seric 			**	If sending to multiple people, mail back
3408238Seric 			**		errors rather than reporting directly.
3418238Seric 			**	In any case, don't mail back errors for
3428238Seric 			**		anything that has happened up to
3438238Seric 			**		now (the other end will do this).
34410197Seric 			**	Truncate our transcript -- the mail has gotten
34510197Seric 			**		to us successfully, and if we have
34610197Seric 			**		to mail this back, it will be easier
34710197Seric 			**		on the reader.
3488238Seric 			**	Then send to everyone.
3498238Seric 			**	Finally give a reply code.  If an error has
3508238Seric 			**		already been given, don't mail a
3518238Seric 			**		message back.
3529339Seric 			**	We goose error returns by clearing error bit.
3538238Seric 			*/
3548238Seric 
35524943Seric 			SmtpPhase = "delivery";
35655012Seric 			if (e->e_nrcpts != 1)
3579378Seric 			{
3589378Seric 				HoldErrs = TRUE;
35916886Seric 				ErrorMode = EM_MAIL;
3609378Seric 			}
36155012Seric 			e->e_flags &= ~EF_FATALERRS;
36255012Seric 			e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp);
3634976Seric 
3644976Seric 			/* send to all recipients */
36555012Seric 			sendall(e, SM_DEFAULT);
36655012Seric 			e->e_to = NULL;
3674976Seric 
36823516Seric 			/* save statistics */
36955012Seric 			markstats(e, (ADDRESS *) NULL);
37023516Seric 
3718238Seric 			/* issue success if appropriate and reset */
3728238Seric 			if (Errors == 0 || HoldErrs)
37358151Seric 				message("250 Ok");
3748238Seric 			else
37555012Seric 				e->e_flags &= ~EF_FATALERRS;
3769339Seric 
3779339Seric 			/* if in a child, pop back to our parent */
3789339Seric 			if (InChild)
3799339Seric 				finis();
38024943Seric 
38124943Seric 			/* clean up a bit */
38258109Seric 			gotmail = FALSE;
38355012Seric 			dropenvelope(e);
38458179Seric 			CurEnv = e = newenvelope(e, CurEnv);
38555012Seric 			e->e_flags = BlankEnvelope.e_flags;
3864549Seric 			break;
3874549Seric 
3884549Seric 		  case CMDRSET:		/* rset -- reset state */
38958151Seric 			message("250 Reset state");
3909339Seric 			if (InChild)
3919339Seric 				finis();
39258109Seric 
39358109Seric 			/* clean up a bit */
39458109Seric 			gotmail = FALSE;
39558109Seric 			dropenvelope(e);
39658179Seric 			CurEnv = e = newenvelope(e, CurEnv);
3979339Seric 			break;
3984549Seric 
3994549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
40058092Seric 		  case CMDEXPN:		/* expn -- expand address */
40158092Seric 			vrfy = c->cmdcode == CMDVRFY;
40258092Seric 			if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN,
40358092Seric 						PrivacyFlags))
40458082Seric 			{
40558151Seric 				message("502 That's none of your business");
40658082Seric 				break;
40758082Seric 			}
40858082Seric 			else if (!gothello &&
40958092Seric 				 bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO,
41058092Seric 						PrivacyFlags))
41158082Seric 			{
41258151Seric 				message("503 I demand that you introduce yourself first");
41358082Seric 				break;
41458082Seric 			}
41558092Seric 			if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0)
4169339Seric 				break;
41725050Seric 			setproctitle("%s: %s", CurHostName, inp);
41855173Seric #ifdef LOG
41958020Seric 			if (LogLevel > 5)
42055173Seric 				syslog(LOG_INFO, "%s: %s", CurHostName, inp);
42155173Seric #endif
4225003Seric 			vrfyqueue = NULL;
4237762Seric 			QuickAbort = TRUE;
42458092Seric 			if (vrfy)
42558092Seric 				e->e_flags |= EF_VRFYONLY;
42658082Seric 			(void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e);
4277762Seric 			if (Errors != 0)
4289339Seric 			{
4299339Seric 				if (InChild)
4309339Seric 					finis();
4317762Seric 				break;
4329339Seric 			}
4335003Seric 			while (vrfyqueue != NULL)
4345003Seric 			{
4355003Seric 				register ADDRESS *a = vrfyqueue->q_next;
4365003Seric 				char *code;
4375003Seric 
4387685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
4395003Seric 					a = a->q_next;
4405003Seric 
4417685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
44258151Seric 					printvrfyaddr(vrfyqueue, a == NULL);
4435003Seric 				else if (a == NULL)
44458151Seric 					message("554 Self destructive alias loop");
4455003Seric 				vrfyqueue = a;
4465003Seric 			}
4479339Seric 			if (InChild)
4489339Seric 				finis();
4494549Seric 			break;
4504549Seric 
4514549Seric 		  case CMDHELP:		/* help -- give user info */
4524577Seric 			help(p);
4534549Seric 			break;
4544549Seric 
4554549Seric 		  case CMDNOOP:		/* noop -- do nothing */
45658151Seric 			message("200 OK");
4574549Seric 			break;
4584549Seric 
4594549Seric 		  case CMDQUIT:		/* quit -- leave mail */
46058151Seric 			message("221 %s closing connection", MyHostName);
4619339Seric 			if (InChild)
4629339Seric 				ExitStat = EX_QUIT;
4634549Seric 			finis();
4644549Seric 
4658544Seric 		  case CMDVERB:		/* set verbose mode */
4668544Seric 			Verbose = TRUE;
46725025Seric 			SendMode = SM_DELIVER;
46858151Seric 			message("200 Verbose mode");
4698544Seric 			break;
4708544Seric 
4719314Seric 		  case CMDONEX:		/* doing one transaction only */
4729378Seric 			OneXact = TRUE;
47358151Seric 			message("200 Only one transaction");
4749314Seric 			break;
4759314Seric 
47636230Skarels # ifdef SMTPDEBUG
4779339Seric 		  case CMDDBGQSHOW:	/* show queues */
4786907Seric 			printf("Send Queue=");
47955012Seric 			printaddr(e->e_sendqueue, TRUE);
4805003Seric 			break;
4817275Seric 
4827275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
4837676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
4847676Seric 			tTflag(p);
48558151Seric 			message("200 Debug set");
4867275Seric 			break;
4877275Seric 
48836230Skarels # else /* not SMTPDEBUG */
48924945Seric 
49036230Skarels 		  case CMDDBGQSHOW:	/* show queues */
49136230Skarels 		  case CMDDBGDEBUG:	/* set debug mode */
49236233Skarels # ifdef LOG
493*58308Seric 			if (LogLevel > 0)
49436230Skarels 				syslog(LOG_NOTICE,
49558020Seric 				    "\"%s\" command from %s (%s)",
49636230Skarels 				    c->cmdname, RealHostName,
49736230Skarels 				    inet_ntoa(RealHostAddr.sin_addr));
49836233Skarels # endif
49936230Skarels 			/* FALL THROUGH */
50036230Skarels # endif /* SMTPDEBUG */
50136230Skarels 
5024549Seric 		  case CMDERROR:	/* unknown command */
50358151Seric 			message("500 Command unrecognized");
5044549Seric 			break;
5054549Seric 
5064549Seric 		  default:
50736230Skarels 			errno = 0;
50858151Seric 			syserr("500 smtp: unknown code %d", c->cmdcode);
5094549Seric 			break;
5104549Seric 		}
5114549Seric 	}
5124549Seric }
5134549Seric /*
5144549Seric **  SKIPWORD -- skip a fixed word.
5154549Seric **
5164549Seric **	Parameters:
5174549Seric **		p -- place to start looking.
5184549Seric **		w -- word to skip.
5194549Seric **
5204549Seric **	Returns:
5214549Seric **		p following w.
5224549Seric **		NULL on error.
5234549Seric **
5244549Seric **	Side Effects:
5254549Seric **		clobbers the p data area.
5264549Seric */
5274549Seric 
5284549Seric static char *
5294549Seric skipword(p, w)
5304549Seric 	register char *p;
5314549Seric 	char *w;
5324549Seric {
5334549Seric 	register char *q;
5344549Seric 
5354549Seric 	/* find beginning of word */
53658050Seric 	while (isascii(*p) && isspace(*p))
5374549Seric 		p++;
5384549Seric 	q = p;
5394549Seric 
5404549Seric 	/* find end of word */
54158050Seric 	while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p)))
5424549Seric 		p++;
54358050Seric 	while (isascii(*p) && isspace(*p))
5444549Seric 		*p++ = '\0';
5454549Seric 	if (*p != ':')
5464549Seric 	{
5474549Seric 	  syntax:
54858151Seric 		message("501 Syntax error");
5494549Seric 		Errors++;
5504549Seric 		return (NULL);
5514549Seric 	}
5524549Seric 	*p++ = '\0';
55358050Seric 	while (isascii(*p) && isspace(*p))
5544549Seric 		p++;
5554549Seric 
5564549Seric 	/* see if the input word matches desired word */
55733725Sbostic 	if (strcasecmp(q, w))
5584549Seric 		goto syntax;
5594549Seric 
5604549Seric 	return (p);
5614549Seric }
5624577Seric /*
56358151Seric **  PRINTVRFYADDR -- print an entry in the verify queue
56458151Seric **
56558151Seric **	Parameters:
56658151Seric **		a -- the address to print
56758151Seric **		last -- set if this is the last one.
56858151Seric **
56958151Seric **	Returns:
57058151Seric **		none.
57158151Seric **
57258151Seric **	Side Effects:
57358151Seric **		Prints the appropriate 250 codes.
57458151Seric */
57558151Seric 
57658151Seric printvrfyaddr(a, last)
57758151Seric 	register ADDRESS *a;
57858151Seric 	bool last;
57958151Seric {
58058151Seric 	char fmtbuf[20];
58158151Seric 
58258151Seric 	strcpy(fmtbuf, "250");
58358151Seric 	fmtbuf[3] = last ? ' ' : '-';
58458151Seric 
58558151Seric 	if (strchr(a->q_paddr, '<') != NULL)
58658151Seric 		strcpy(&fmtbuf[4], "%s");
58758151Seric 	else if (a->q_fullname == NULL)
58858151Seric 		strcpy(&fmtbuf[4], "<%s>");
58958151Seric 	else
59058151Seric 	{
59158151Seric 		strcpy(&fmtbuf[4], "%s <%s>");
59258151Seric 		message(fmtbuf, a->q_fullname, a->q_paddr);
59358151Seric 		return;
59458151Seric 	}
59558151Seric 	message(fmtbuf, a->q_paddr);
59658151Seric }
59758151Seric /*
5984577Seric **  HELP -- implement the HELP command.
5994577Seric **
6004577Seric **	Parameters:
6014577Seric **		topic -- the topic we want help for.
6024577Seric **
6034577Seric **	Returns:
6044577Seric **		none.
6054577Seric **
6064577Seric **	Side Effects:
6074577Seric **		outputs the help file to message output.
6084577Seric */
6094577Seric 
6104577Seric help(topic)
6114577Seric 	char *topic;
6124577Seric {
6134577Seric 	register FILE *hf;
6144577Seric 	int len;
6154577Seric 	char buf[MAXLINE];
6164577Seric 	bool noinfo;
6174577Seric 
6188269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
6194577Seric 	{
6204577Seric 		/* no help */
62111931Seric 		errno = 0;
62258151Seric 		message("502 HELP not implemented");
6234577Seric 		return;
6244577Seric 	}
6254577Seric 
62649669Seric 	if (topic == NULL || *topic == '\0')
62749669Seric 		topic = "smtp";
62849669Seric 	else
62949669Seric 		makelower(topic);
63049669Seric 
6314577Seric 	len = strlen(topic);
6324577Seric 	noinfo = TRUE;
6334577Seric 
6344577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
6354577Seric 	{
6364577Seric 		if (strncmp(buf, topic, len) == 0)
6374577Seric 		{
6384577Seric 			register char *p;
6394577Seric 
64056795Seric 			p = strchr(buf, '\t');
6414577Seric 			if (p == NULL)
6424577Seric 				p = buf;
6434577Seric 			else
6444577Seric 				p++;
6454577Seric 			fixcrlf(p, TRUE);
64658151Seric 			message("214-%s", p);
6474577Seric 			noinfo = FALSE;
6484577Seric 		}
6494577Seric 	}
6504577Seric 
6514577Seric 	if (noinfo)
65258151Seric 		message("504 HELP topic unknown");
6534577Seric 	else
65458151Seric 		message("214 End of HELP info");
6554628Seric 	(void) fclose(hf);
6564577Seric }
6578544Seric /*
6589339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
6599339Seric **
6609339Seric **	Parameters:
6619339Seric **		label -- a string used in error messages
6629339Seric **
6639339Seric **	Returns:
6649339Seric **		zero in the child
6659339Seric **		one in the parent
6669339Seric **
6679339Seric **	Side Effects:
6689339Seric **		none.
6699339Seric */
6708544Seric 
67155012Seric runinchild(label, e)
6729339Seric 	char *label;
67355012Seric 	register ENVELOPE *e;
6749339Seric {
6759339Seric 	int childpid;
6769339Seric 
67716158Seric 	if (!OneXact)
6789339Seric 	{
67916158Seric 		childpid = dofork();
68016158Seric 		if (childpid < 0)
68116158Seric 		{
68216158Seric 			syserr("%s: cannot fork", label);
68316158Seric 			return (1);
68416158Seric 		}
68516158Seric 		if (childpid > 0)
68616158Seric 		{
68716158Seric 			auto int st;
6889339Seric 
68916158Seric 			/* parent -- wait for child to complete */
69016158Seric 			st = waitfor(childpid);
69116158Seric 			if (st == -1)
69216158Seric 				syserr("%s: lost child", label);
6939339Seric 
69416158Seric 			/* if we exited on a QUIT command, complete the process */
69516158Seric 			if (st == (EX_QUIT << 8))
69616158Seric 				finis();
6979339Seric 
69816158Seric 			return (1);
69916158Seric 		}
70016158Seric 		else
70116158Seric 		{
70216158Seric 			/* child */
70316158Seric 			InChild = TRUE;
70425050Seric 			QuickAbort = FALSE;
70555012Seric 			clearenvelope(e, FALSE);
70616158Seric 		}
7079339Seric 	}
70815256Seric 
70916158Seric 	/* open alias database */
71055012Seric 	initaliases(AliasFile, FALSE, e);
71116158Seric 
71216158Seric 	return (0);
7139339Seric }
7149339Seric 
71556795Seric # endif /* SMTP */
716