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*58323Seric static char sccsid[] = "@(#)srvrsmtp.c	6.19 (Berkeley) 02/28/93 (with SMTP)";
1433731Sbostic #else
15*58323Seric static char sccsid[] = "@(#)srvrsmtp.c	6.19 (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 */
56*58323Seric # define CMDEHLO	11	/* ehlo -- extended helo (RFC 1425) */
5758092Seric /* non-standard commands */
5858092Seric # define CMDONEX	16	/* onex -- sending one transaction only */
5958092Seric # define CMDVERB	17	/* verb -- go into verbose mode */
6036230Skarels /* debugging-only commands, only enabled if SMTPDEBUG is defined */
6158092Seric # define CMDDBGQSHOW	24	/* showq -- show send queue */
6258092Seric # define CMDDBGDEBUG	25	/* debug -- set debug mode */
634549Seric 
644549Seric static struct cmd	CmdTab[] =
654549Seric {
664549Seric 	"mail",		CMDMAIL,
674976Seric 	"rcpt",		CMDRCPT,
684549Seric 	"data",		CMDDATA,
694549Seric 	"rset",		CMDRSET,
704549Seric 	"vrfy",		CMDVRFY,
7158092Seric 	"expn",		CMDEXPN,
724549Seric 	"help",		CMDHELP,
734549Seric 	"noop",		CMDNOOP,
744549Seric 	"quit",		CMDQUIT,
754976Seric 	"helo",		CMDHELO,
76*58323Seric 	"ehlo",		CMDEHLO,
778544Seric 	"verb",		CMDVERB,
789314Seric 	"onex",		CMDONEX,
7936230Skarels 	/*
8036230Skarels 	 * remaining commands are here only
8136230Skarels 	 * to trap and log attempts to use them
8236230Skarels 	 */
839339Seric 	"showq",	CMDDBGQSHOW,
848544Seric 	"debug",	CMDDBGDEBUG,
854549Seric 	NULL,		CMDERROR,
864549Seric };
874549Seric 
889339Seric bool	InChild = FALSE;		/* true if running in a subprocess */
899378Seric bool	OneXact = FALSE;		/* one xaction only this run */
9011146Seric 
919339Seric #define EX_QUIT		22		/* special code for QUIT command */
928544Seric 
9355012Seric smtp(e)
9455012Seric 	register ENVELOPE *e;
954549Seric {
964549Seric 	register char *p;
978544Seric 	register struct cmd *c;
984549Seric 	char *cmd;
9946928Sbostic 	static char *skipword();
1005003Seric 	auto ADDRESS *vrfyqueue;
10112612Seric 	ADDRESS *a;
10230448Seric 	char *sendinghost;
10358109Seric 	bool gotmail;			/* mail command received */
10458092Seric 	bool gothello;			/* helo command received */
10558092Seric 	bool vrfy;			/* set if this is a vrfy command */
106*58323Seric 	char *protocol;			/* sending protocol */
1078544Seric 	char inp[MAXLINE];
10857232Seric 	char cmdbuf[MAXLINE];
1097124Seric 	extern char Version[];
11011151Seric 	extern char *macvalue();
11112612Seric 	extern ADDRESS *recipient();
11224943Seric 	extern ENVELOPE BlankEnvelope;
11324943Seric 	extern ENVELOPE *newenvelope();
1144549Seric 
11558109Seric 	gotmail = FALSE;
1167363Seric 	if (OutChannel != stdout)
1177363Seric 	{
1187363Seric 		/* arrange for debugging output to go to remote host */
1197363Seric 		(void) close(1);
1207363Seric 		(void) dup(fileno(OutChannel));
1217363Seric 	}
12255012Seric 	settime(e);
12357642Seric 	CurHostName = RealHostName;
12457642Seric 	setproctitle("srvrsmtp %s", CurHostName);
12558050Seric 	expand("\201e", inp, &inp[sizeof inp], e);
12658151Seric 	message("220 %s", inp);
12724943Seric 	SmtpPhase = "startup";
12830448Seric 	sendinghost = NULL;
12958082Seric 	gothello = FALSE;
1304549Seric 	for (;;)
1314549Seric 	{
13212612Seric 		/* arrange for backout */
13312612Seric 		if (setjmp(TopFrame) > 0 && InChild)
13412612Seric 			finis();
13512612Seric 		QuickAbort = FALSE;
13612612Seric 		HoldErrs = FALSE;
13751951Seric 		LogUsrErrs = FALSE;
13858092Seric 		e->e_flags &= ~EF_VRFYONLY;
13912612Seric 
1407356Seric 		/* setup for the read */
14155012Seric 		e->e_to = NULL;
1424577Seric 		Errors = 0;
1437275Seric 		(void) fflush(stdout);
1447356Seric 
1457356Seric 		/* read the input line */
14658109Seric 		p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand);
1477356Seric 
1487685Seric 		/* handle errors */
1497356Seric 		if (p == NULL)
1507356Seric 		{
1514549Seric 			/* end of file, just die */
15258151Seric 			message("421 %s Lost input channel from %s",
15325050Seric 				MyHostName, CurHostName);
15455464Seric #ifdef LOG
15558020Seric 			if (LogLevel > 1)
15655464Seric 				syslog(LOG_NOTICE, "lost input channel from %s",
15755464Seric 					CurHostName);
15855464Seric #endif
15958069Seric 			if (InChild)
16058069Seric 				ExitStat = EX_QUIT;
1614549Seric 			finis();
1624549Seric 		}
1634549Seric 
1644549Seric 		/* clean up end of line */
1654558Seric 		fixcrlf(inp, TRUE);
1664549Seric 
1674713Seric 		/* echo command to transcript */
16855012Seric 		if (e->e_xfp != NULL)
16955012Seric 			fprintf(e->e_xfp, "<<< %s\n", inp);
1704713Seric 
1714549Seric 		/* break off command */
17258050Seric 		for (p = inp; isascii(*p) && isspace(*p); p++)
1734549Seric 			continue;
17457232Seric 		cmd = cmdbuf;
17558050Seric 		while (*p != '\0' &&
17658050Seric 		       !(isascii(*p) && isspace(*p)) &&
17758050Seric 		       cmd < &cmdbuf[sizeof cmdbuf - 2])
17824981Seric 			*cmd++ = *p++;
17924981Seric 		*cmd = '\0';
1804549Seric 
18125691Seric 		/* throw away leading whitespace */
18258050Seric 		while (isascii(*p) && isspace(*p))
18325691Seric 			p++;
18425691Seric 
1854549Seric 		/* decode command */
1864549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1874549Seric 		{
18833725Sbostic 			if (!strcasecmp(c->cmdname, cmdbuf))
1894549Seric 				break;
1904549Seric 		}
1914549Seric 
19251954Seric 		/* reset errors */
19351954Seric 		errno = 0;
19451954Seric 
1954549Seric 		/* process command */
1964549Seric 		switch (c->cmdcode)
1974549Seric 		{
1984976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
199*58323Seric 		  case CMDEHLO:		/* extended hello */
200*58323Seric 			if (c->cmdcode == CMDEHLO)
201*58323Seric 			{
202*58323Seric 				protocol = "ESMTP";
203*58323Seric 				SmtpPhase = "EHLO";
204*58323Seric 			}
205*58323Seric 			else
206*58323Seric 			{
207*58323Seric 				protocol = "SMTP";
208*58323Seric 				SmtpPhase = "HELO";
209*58323Seric 			}
21025050Seric 			setproctitle("%s: %s", CurHostName, inp);
21158109Seric 			if (strcasecmp(p, MyHostName) == 0)
21214877Seric 			{
21336230Skarels 				/*
21458109Seric 				**  Didn't know about alias or MX,
21558109Seric 				**  or connected to an echo server
21658109Seric 				*/
21758109Seric 
21858151Seric 				message("553 %s config error: mail loops back to myself",
21947570Seric 					MyHostName);
22014877Seric 				break;
22114877Seric 			}
22258308Seric 			if (strcasecmp(p, RealHostName) != 0)
22311146Seric 			{
22424981Seric 				char hostbuf[MAXNAME];
22511146Seric 
22624981Seric 				(void) sprintf(hostbuf, "%s (%s)", p, RealHostName);
22730448Seric 				sendinghost = newstr(hostbuf);
22811146Seric 			}
22911146Seric 			else
23030448Seric 				sendinghost = newstr(p);
231*58323Seric 
232*58323Seric 			/* send ext. message -- old systems must ignore */
233*58323Seric 			message("250-%s Hello %s, pleased to meet you",
23436230Skarels 				MyHostName, sendinghost);
235*58323Seric 			if (!bitset(PRIV_NOEXPN, PrivacyFlags))
236*58323Seric 				message("250-EXPN");
237*58323Seric 			message("250 HELP");
23858082Seric 			gothello = TRUE;
2394976Seric 			break;
2404976Seric 
2414549Seric 		  case CMDMAIL:		/* mail -- designate sender */
24224943Seric 			SmtpPhase = "MAIL";
24324943Seric 
24411151Seric 			/* force a sending host even if no HELO given */
24558064Seric 			if (sendinghost == NULL && macvalue('s', e) == NULL)
24630448Seric 				sendinghost = RealHostName;
24711151Seric 
2489314Seric 			/* check for validity of this command */
24958082Seric 			if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags))
25058082Seric 			{
25158151Seric 				message("503 Polite people say HELO first");
25258082Seric 				break;
25358082Seric 			}
25458109Seric 			if (gotmail)
2554558Seric 			{
25658151Seric 				message("503 Sender already specified");
2574558Seric 				break;
2584558Seric 			}
2599339Seric 			if (InChild)
2609339Seric 			{
26136230Skarels 				errno = 0;
26258151Seric 				syserr("503 Nested MAIL command: MAIL %s", p);
26358069Seric 				finis();
2649339Seric 			}
26558082Seric 			if (!enoughspace())
26658082Seric 			{
26758151Seric 				message("452 Insufficient disk space; try again later");
26858082Seric 				break;
26958082Seric 			}
2709339Seric 
2719339Seric 			/* fork a subprocess to process this command */
27255012Seric 			if (runinchild("SMTP-MAIL", e) > 0)
2739339Seric 				break;
27458064Seric 			if (sendinghost != NULL)
27558064Seric 				define('s', sendinghost, e);
276*58323Seric 			if (protocol == NULL)
277*58323Seric 				protocol = "SMTP";
278*58323Seric 			define('r', protocol, e);
27955012Seric 			initsys(e);
28057389Seric 			setproctitle("%s %s: %s", e->e_id, CurHostName, inp);
2819339Seric 
2829339Seric 			/* child -- go do the processing */
2834549Seric 			p = skipword(p, "from");
2844549Seric 			if (p == NULL)
2854549Seric 				break;
28657977Seric 			if (setjmp(TopFrame) > 0)
28758147Seric 			{
28858147Seric 				/* this failed -- undo work */
28958147Seric 				if (InChild)
29058147Seric 					finis();
29157977Seric 				break;
29258147Seric 			}
29357977Seric 			QuickAbort = TRUE;
29455012Seric 			setsender(p, e);
29558151Seric 			message("250 Sender ok");
29658147Seric 			gotmail = TRUE;
2974549Seric 			break;
2984549Seric 
2994976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
30024943Seric 			SmtpPhase = "RCPT";
30157389Seric 			setproctitle("%s %s: %s", e->e_id, CurHostName, inp);
30212612Seric 			if (setjmp(TopFrame) > 0)
30314785Seric 			{
30455012Seric 				e->e_flags &= ~EF_FATALERRS;
30512612Seric 				break;
30614785Seric 			}
30712612Seric 			QuickAbort = TRUE;
30851951Seric 			LogUsrErrs = TRUE;
30958093Seric 
31058093Seric 			/* optimization -- if queueing, don't expand aliases */
31158093Seric 			if (SendMode == SM_QUEUE)
31258093Seric 				e->e_flags |= EF_VRFYONLY;
31358093Seric 
3144549Seric 			p = skipword(p, "to");
3154549Seric 			if (p == NULL)
3164549Seric 				break;
317*58323Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', e);
31812612Seric 			if (a == NULL)
31912612Seric 				break;
32016886Seric 			a->q_flags |= QPRIMARY;
32155012Seric 			a = recipient(a, &e->e_sendqueue, e);
32212612Seric 			if (Errors != 0)
32312612Seric 				break;
32412612Seric 
32512612Seric 			/* no errors during parsing, but might be a duplicate */
32655012Seric 			e->e_to = p;
32712612Seric 			if (!bitset(QBADADDR, a->q_flags))
32858151Seric 				message("250 Recipient ok");
32912612Seric 			else
3304549Seric 			{
33112612Seric 				/* punt -- should keep message in ADDRESS.... */
33258151Seric 				message("550 Addressee unknown");
3334549Seric 			}
33455012Seric 			e->e_to = NULL;
3354549Seric 			break;
3364549Seric 
3374549Seric 		  case CMDDATA:		/* data -- text of mail */
33824943Seric 			SmtpPhase = "DATA";
33958109Seric 			if (!gotmail)
3404549Seric 			{
34158151Seric 				message("503 Need MAIL command");
3424976Seric 				break;
3434549Seric 			}
34455012Seric 			else if (e->e_nrcpts <= 0)
3454549Seric 			{
34658151Seric 				message("503 Need RCPT (recipient)");
3474976Seric 				break;
3484549Seric 			}
3494976Seric 
3504976Seric 			/* collect the text of the message */
35124943Seric 			SmtpPhase = "collect";
35257389Seric 			setproctitle("%s %s: %s", e->e_id, CurHostName, inp);
35355012Seric 			collect(TRUE, e);
3544976Seric 			if (Errors != 0)
3554976Seric 				break;
3564976Seric 
3578238Seric 			/*
3588238Seric 			**  Arrange to send to everyone.
3598238Seric 			**	If sending to multiple people, mail back
3608238Seric 			**		errors rather than reporting directly.
3618238Seric 			**	In any case, don't mail back errors for
3628238Seric 			**		anything that has happened up to
3638238Seric 			**		now (the other end will do this).
36410197Seric 			**	Truncate our transcript -- the mail has gotten
36510197Seric 			**		to us successfully, and if we have
36610197Seric 			**		to mail this back, it will be easier
36710197Seric 			**		on the reader.
3688238Seric 			**	Then send to everyone.
3698238Seric 			**	Finally give a reply code.  If an error has
3708238Seric 			**		already been given, don't mail a
3718238Seric 			**		message back.
3729339Seric 			**	We goose error returns by clearing error bit.
3738238Seric 			*/
3748238Seric 
37524943Seric 			SmtpPhase = "delivery";
37655012Seric 			if (e->e_nrcpts != 1)
3779378Seric 			{
3789378Seric 				HoldErrs = TRUE;
37916886Seric 				ErrorMode = EM_MAIL;
3809378Seric 			}
38155012Seric 			e->e_flags &= ~EF_FATALERRS;
38255012Seric 			e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp);
3834976Seric 
3844976Seric 			/* send to all recipients */
38555012Seric 			sendall(e, SM_DEFAULT);
38655012Seric 			e->e_to = NULL;
3874976Seric 
38823516Seric 			/* save statistics */
38955012Seric 			markstats(e, (ADDRESS *) NULL);
39023516Seric 
3918238Seric 			/* issue success if appropriate and reset */
3928238Seric 			if (Errors == 0 || HoldErrs)
39358151Seric 				message("250 Ok");
3948238Seric 			else
39555012Seric 				e->e_flags &= ~EF_FATALERRS;
3969339Seric 
3979339Seric 			/* if in a child, pop back to our parent */
3989339Seric 			if (InChild)
3999339Seric 				finis();
40024943Seric 
40124943Seric 			/* clean up a bit */
40258109Seric 			gotmail = FALSE;
40355012Seric 			dropenvelope(e);
40458179Seric 			CurEnv = e = newenvelope(e, CurEnv);
40555012Seric 			e->e_flags = BlankEnvelope.e_flags;
4064549Seric 			break;
4074549Seric 
4084549Seric 		  case CMDRSET:		/* rset -- reset state */
40958151Seric 			message("250 Reset state");
4109339Seric 			if (InChild)
4119339Seric 				finis();
41258109Seric 
41358109Seric 			/* clean up a bit */
41458109Seric 			gotmail = FALSE;
41558109Seric 			dropenvelope(e);
41658179Seric 			CurEnv = e = newenvelope(e, CurEnv);
4179339Seric 			break;
4184549Seric 
4194549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
42058092Seric 		  case CMDEXPN:		/* expn -- expand address */
42158092Seric 			vrfy = c->cmdcode == CMDVRFY;
42258092Seric 			if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN,
42358092Seric 						PrivacyFlags))
42458082Seric 			{
42558151Seric 				message("502 That's none of your business");
42658082Seric 				break;
42758082Seric 			}
42858082Seric 			else if (!gothello &&
42958092Seric 				 bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO,
43058092Seric 						PrivacyFlags))
43158082Seric 			{
43258151Seric 				message("503 I demand that you introduce yourself first");
43358082Seric 				break;
43458082Seric 			}
43558092Seric 			if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0)
4369339Seric 				break;
43725050Seric 			setproctitle("%s: %s", CurHostName, inp);
43855173Seric #ifdef LOG
43958020Seric 			if (LogLevel > 5)
44055173Seric 				syslog(LOG_INFO, "%s: %s", CurHostName, inp);
44155173Seric #endif
4425003Seric 			vrfyqueue = NULL;
4437762Seric 			QuickAbort = TRUE;
44458092Seric 			if (vrfy)
44558092Seric 				e->e_flags |= EF_VRFYONLY;
44658082Seric 			(void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e);
4477762Seric 			if (Errors != 0)
4489339Seric 			{
4499339Seric 				if (InChild)
4509339Seric 					finis();
4517762Seric 				break;
4529339Seric 			}
4535003Seric 			while (vrfyqueue != NULL)
4545003Seric 			{
4555003Seric 				register ADDRESS *a = vrfyqueue->q_next;
4565003Seric 				char *code;
4575003Seric 
4587685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
4595003Seric 					a = a->q_next;
4605003Seric 
4617685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
46258151Seric 					printvrfyaddr(vrfyqueue, a == NULL);
4635003Seric 				else if (a == NULL)
46458151Seric 					message("554 Self destructive alias loop");
4655003Seric 				vrfyqueue = a;
4665003Seric 			}
4679339Seric 			if (InChild)
4689339Seric 				finis();
4694549Seric 			break;
4704549Seric 
4714549Seric 		  case CMDHELP:		/* help -- give user info */
4724577Seric 			help(p);
4734549Seric 			break;
4744549Seric 
4754549Seric 		  case CMDNOOP:		/* noop -- do nothing */
47658151Seric 			message("200 OK");
4774549Seric 			break;
4784549Seric 
4794549Seric 		  case CMDQUIT:		/* quit -- leave mail */
48058151Seric 			message("221 %s closing connection", MyHostName);
4819339Seric 			if (InChild)
4829339Seric 				ExitStat = EX_QUIT;
4834549Seric 			finis();
4844549Seric 
4858544Seric 		  case CMDVERB:		/* set verbose mode */
4868544Seric 			Verbose = TRUE;
48725025Seric 			SendMode = SM_DELIVER;
48858151Seric 			message("200 Verbose mode");
4898544Seric 			break;
4908544Seric 
4919314Seric 		  case CMDONEX:		/* doing one transaction only */
4929378Seric 			OneXact = TRUE;
49358151Seric 			message("200 Only one transaction");
4949314Seric 			break;
4959314Seric 
49636230Skarels # ifdef SMTPDEBUG
4979339Seric 		  case CMDDBGQSHOW:	/* show queues */
4986907Seric 			printf("Send Queue=");
49955012Seric 			printaddr(e->e_sendqueue, TRUE);
5005003Seric 			break;
5017275Seric 
5027275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
5037676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
5047676Seric 			tTflag(p);
50558151Seric 			message("200 Debug set");
5067275Seric 			break;
5077275Seric 
50836230Skarels # else /* not SMTPDEBUG */
50924945Seric 
51036230Skarels 		  case CMDDBGQSHOW:	/* show queues */
51136230Skarels 		  case CMDDBGDEBUG:	/* set debug mode */
51236233Skarels # ifdef LOG
51358308Seric 			if (LogLevel > 0)
51436230Skarels 				syslog(LOG_NOTICE,
51558020Seric 				    "\"%s\" command from %s (%s)",
51636230Skarels 				    c->cmdname, RealHostName,
51736230Skarels 				    inet_ntoa(RealHostAddr.sin_addr));
51836233Skarels # endif
51936230Skarels 			/* FALL THROUGH */
52036230Skarels # endif /* SMTPDEBUG */
52136230Skarels 
5224549Seric 		  case CMDERROR:	/* unknown command */
52358151Seric 			message("500 Command unrecognized");
5244549Seric 			break;
5254549Seric 
5264549Seric 		  default:
52736230Skarels 			errno = 0;
52858151Seric 			syserr("500 smtp: unknown code %d", c->cmdcode);
5294549Seric 			break;
5304549Seric 		}
5314549Seric 	}
5324549Seric }
5334549Seric /*
5344549Seric **  SKIPWORD -- skip a fixed word.
5354549Seric **
5364549Seric **	Parameters:
5374549Seric **		p -- place to start looking.
5384549Seric **		w -- word to skip.
5394549Seric **
5404549Seric **	Returns:
5414549Seric **		p following w.
5424549Seric **		NULL on error.
5434549Seric **
5444549Seric **	Side Effects:
5454549Seric **		clobbers the p data area.
5464549Seric */
5474549Seric 
5484549Seric static char *
5494549Seric skipword(p, w)
5504549Seric 	register char *p;
5514549Seric 	char *w;
5524549Seric {
5534549Seric 	register char *q;
5544549Seric 
5554549Seric 	/* find beginning of word */
55658050Seric 	while (isascii(*p) && isspace(*p))
5574549Seric 		p++;
5584549Seric 	q = p;
5594549Seric 
5604549Seric 	/* find end of word */
56158050Seric 	while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p)))
5624549Seric 		p++;
56358050Seric 	while (isascii(*p) && isspace(*p))
5644549Seric 		*p++ = '\0';
5654549Seric 	if (*p != ':')
5664549Seric 	{
5674549Seric 	  syntax:
56858151Seric 		message("501 Syntax error");
5694549Seric 		Errors++;
5704549Seric 		return (NULL);
5714549Seric 	}
5724549Seric 	*p++ = '\0';
57358050Seric 	while (isascii(*p) && isspace(*p))
5744549Seric 		p++;
5754549Seric 
5764549Seric 	/* see if the input word matches desired word */
57733725Sbostic 	if (strcasecmp(q, w))
5784549Seric 		goto syntax;
5794549Seric 
5804549Seric 	return (p);
5814549Seric }
5824577Seric /*
58358151Seric **  PRINTVRFYADDR -- print an entry in the verify queue
58458151Seric **
58558151Seric **	Parameters:
58658151Seric **		a -- the address to print
58758151Seric **		last -- set if this is the last one.
58858151Seric **
58958151Seric **	Returns:
59058151Seric **		none.
59158151Seric **
59258151Seric **	Side Effects:
59358151Seric **		Prints the appropriate 250 codes.
59458151Seric */
59558151Seric 
59658151Seric printvrfyaddr(a, last)
59758151Seric 	register ADDRESS *a;
59858151Seric 	bool last;
59958151Seric {
60058151Seric 	char fmtbuf[20];
60158151Seric 
60258151Seric 	strcpy(fmtbuf, "250");
60358151Seric 	fmtbuf[3] = last ? ' ' : '-';
60458151Seric 
60558151Seric 	if (strchr(a->q_paddr, '<') != NULL)
60658151Seric 		strcpy(&fmtbuf[4], "%s");
60758151Seric 	else if (a->q_fullname == NULL)
60858151Seric 		strcpy(&fmtbuf[4], "<%s>");
60958151Seric 	else
61058151Seric 	{
61158151Seric 		strcpy(&fmtbuf[4], "%s <%s>");
61258151Seric 		message(fmtbuf, a->q_fullname, a->q_paddr);
61358151Seric 		return;
61458151Seric 	}
61558151Seric 	message(fmtbuf, a->q_paddr);
61658151Seric }
61758151Seric /*
6184577Seric **  HELP -- implement the HELP command.
6194577Seric **
6204577Seric **	Parameters:
6214577Seric **		topic -- the topic we want help for.
6224577Seric **
6234577Seric **	Returns:
6244577Seric **		none.
6254577Seric **
6264577Seric **	Side Effects:
6274577Seric **		outputs the help file to message output.
6284577Seric */
6294577Seric 
6304577Seric help(topic)
6314577Seric 	char *topic;
6324577Seric {
6334577Seric 	register FILE *hf;
6344577Seric 	int len;
6354577Seric 	char buf[MAXLINE];
6364577Seric 	bool noinfo;
6374577Seric 
6388269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
6394577Seric 	{
6404577Seric 		/* no help */
64111931Seric 		errno = 0;
64258151Seric 		message("502 HELP not implemented");
6434577Seric 		return;
6444577Seric 	}
6454577Seric 
64649669Seric 	if (topic == NULL || *topic == '\0')
64749669Seric 		topic = "smtp";
64849669Seric 	else
64949669Seric 		makelower(topic);
65049669Seric 
6514577Seric 	len = strlen(topic);
6524577Seric 	noinfo = TRUE;
6534577Seric 
6544577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
6554577Seric 	{
6564577Seric 		if (strncmp(buf, topic, len) == 0)
6574577Seric 		{
6584577Seric 			register char *p;
6594577Seric 
66056795Seric 			p = strchr(buf, '\t');
6614577Seric 			if (p == NULL)
6624577Seric 				p = buf;
6634577Seric 			else
6644577Seric 				p++;
6654577Seric 			fixcrlf(p, TRUE);
66658151Seric 			message("214-%s", p);
6674577Seric 			noinfo = FALSE;
6684577Seric 		}
6694577Seric 	}
6704577Seric 
6714577Seric 	if (noinfo)
67258151Seric 		message("504 HELP topic unknown");
6734577Seric 	else
67458151Seric 		message("214 End of HELP info");
6754628Seric 	(void) fclose(hf);
6764577Seric }
6778544Seric /*
6789339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
6799339Seric **
6809339Seric **	Parameters:
6819339Seric **		label -- a string used in error messages
6829339Seric **
6839339Seric **	Returns:
6849339Seric **		zero in the child
6859339Seric **		one in the parent
6869339Seric **
6879339Seric **	Side Effects:
6889339Seric **		none.
6899339Seric */
6908544Seric 
69155012Seric runinchild(label, e)
6929339Seric 	char *label;
69355012Seric 	register ENVELOPE *e;
6949339Seric {
6959339Seric 	int childpid;
6969339Seric 
69716158Seric 	if (!OneXact)
6989339Seric 	{
69916158Seric 		childpid = dofork();
70016158Seric 		if (childpid < 0)
70116158Seric 		{
70216158Seric 			syserr("%s: cannot fork", label);
70316158Seric 			return (1);
70416158Seric 		}
70516158Seric 		if (childpid > 0)
70616158Seric 		{
70716158Seric 			auto int st;
7089339Seric 
70916158Seric 			/* parent -- wait for child to complete */
71016158Seric 			st = waitfor(childpid);
71116158Seric 			if (st == -1)
71216158Seric 				syserr("%s: lost child", label);
7139339Seric 
71416158Seric 			/* if we exited on a QUIT command, complete the process */
71516158Seric 			if (st == (EX_QUIT << 8))
71616158Seric 				finis();
7179339Seric 
71816158Seric 			return (1);
71916158Seric 		}
72016158Seric 		else
72116158Seric 		{
72216158Seric 			/* child */
72316158Seric 			InChild = TRUE;
72425050Seric 			QuickAbort = FALSE;
72555012Seric 			clearenvelope(e, FALSE);
72616158Seric 		}
7279339Seric 	}
72815256Seric 
72916158Seric 	/* open alias database */
73055012Seric 	initaliases(AliasFile, FALSE, e);
73116158Seric 
73216158Seric 	return (0);
7339339Seric }
7349339Seric 
73556795Seric # endif /* SMTP */
736