1*4549Seric # include "sendmail.h"
2*4549Seric 
3*4549Seric /*
4*4549Seric **  SMTP -- run the SMTP protocol.
5*4549Seric **
6*4549Seric **	Parameters:
7*4549Seric **		none.
8*4549Seric **
9*4549Seric **	Returns:
10*4549Seric **		never.
11*4549Seric **
12*4549Seric **	Side Effects:
13*4549Seric **		Reads commands from the input channel and processes
14*4549Seric **			them.
15*4549Seric */
16*4549Seric 
17*4549Seric struct cmd
18*4549Seric {
19*4549Seric 	char	*cmdname;	/* command name */
20*4549Seric 	int	cmdcode;	/* internal code, see below */
21*4549Seric };
22*4549Seric 
23*4549Seric /* values for cmdcode */
24*4549Seric # define CMDERROR	0	/* bad command */
25*4549Seric # define CMDMAIL	1	/* mail -- designate sender */
26*4549Seric # define CMDMRCP	2	/* mrcp -- designate recipient */
27*4549Seric # define CMDDATA	3	/* data -- send message text */
28*4549Seric # define CMDDOIT	4	/* doit -- actually do delivery */
29*4549Seric # define CMDRSET	5	/* rset -- reset state */
30*4549Seric # define CMDVRFY	6	/* vrfy -- verify address */
31*4549Seric # define CMDHELP	7	/* help -- give usage info */
32*4549Seric # define CMDNOOP	8	/* noop -- do nothing */
33*4549Seric # define CMDQUIT	9	/* quit -- close connection and die */
34*4549Seric 
35*4549Seric static struct cmd	CmdTab[] =
36*4549Seric {
37*4549Seric 	"mail",		CMDMAIL,
38*4549Seric 	"mrcp",		CMDMRCP,
39*4549Seric 	"data",		CMDDATA,
40*4549Seric 	"doit",		CMDDOIT,
41*4549Seric 	"rset",		CMDRSET,
42*4549Seric 	"vrfy",		CMDVRFY,
43*4549Seric 	"help",		CMDHELP,
44*4549Seric 	"noop",		CMDNOOP,
45*4549Seric 	"quit",		CMDQUIT,
46*4549Seric 	NULL,		CMDERROR,
47*4549Seric };
48*4549Seric 
49*4549Seric smtp()
50*4549Seric {
51*4549Seric 	char inp[MAXLINE];
52*4549Seric 	register char *p;
53*4549Seric 	struct cmd *c;
54*4549Seric 	char *cmd;
55*4549Seric 	extern char *skipword();
56*4549Seric 	extern bool sameword();
57*4549Seric 	bool hasmail;			/* mail command received */
58*4549Seric 	bool hasmrcp;			/* has a recipient */
59*4549Seric 	bool hasdata;			/* has mail data */
60*4549Seric 
61*4549Seric 	/*%%%*/	HostName = "XYZZY";
62*4549Seric 	hasmail = hasmrcp = hasdata = FALSE;
63*4549Seric 	message("220", "%s Sendmail at your service", HostName);
64*4549Seric 	for (;;)
65*4549Seric 	{
66*4549Seric 		To = NULL;
67*4549Seric 		Errors = 0;
68*4549Seric 		if (fgets(inp, sizeof inp, InChannel) == NULL)
69*4549Seric 		{
70*4549Seric 			/* end of file, just die */
71*4549Seric 			message("421", "Lost input channel");
72*4549Seric 			finis();
73*4549Seric 		}
74*4549Seric 
75*4549Seric 		/* clean up end of line */
76*4549Seric 		p = index(inp, '\n');
77*4549Seric 		if (p != NULL)
78*4549Seric 			*p = '\0';
79*4549Seric 		p = index(inp, '\r');
80*4549Seric 		if (p != NULL)
81*4549Seric 			*p = '\0';
82*4549Seric 
83*4549Seric 		/* break off command */
84*4549Seric 		for (p = inp; isspace(*p); p++)
85*4549Seric 			continue;
86*4549Seric 		cmd = p;
87*4549Seric 		while (*++p != '\0' && !isspace(*p))
88*4549Seric 			continue;
89*4549Seric 		if (*p != '\0')
90*4549Seric 			*p++ = '\0';
91*4549Seric 
92*4549Seric 		/* decode command */
93*4549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
94*4549Seric 		{
95*4549Seric 			if (sameword(c->cmdname, cmd))
96*4549Seric 				break;
97*4549Seric 		}
98*4549Seric 
99*4549Seric 		/* process command */
100*4549Seric 		switch (c->cmdcode)
101*4549Seric 		{
102*4549Seric 		  case CMDMAIL:		/* mail -- designate sender */
103*4549Seric 			p = skipword(p, "from");
104*4549Seric 			if (p == NULL)
105*4549Seric 				break;
106*4549Seric 			if (index(p, ',') != NULL)
107*4549Seric 			{
108*4549Seric 				message("501", "Source routing not implemented");
109*4549Seric 				Errors++;
110*4549Seric 				break;
111*4549Seric 			}
112*4549Seric 			setsender(p);
113*4549Seric 			if (Errors == 0)
114*4549Seric 			{
115*4549Seric 				message("250", "Sender ok");
116*4549Seric 				hasmail = TRUE;
117*4549Seric 			}
118*4549Seric 			break;
119*4549Seric 
120*4549Seric 		  case CMDMRCP:		/* mrcp -- designate recipient */
121*4549Seric 			p = skipword(p, "to");
122*4549Seric 			if (p == NULL)
123*4549Seric 				break;
124*4549Seric 			if (index(p, ',') != NULL)
125*4549Seric 			{
126*4549Seric 				message("501", "Source routing not implemented");
127*4549Seric 				Errors++;
128*4549Seric 				break;
129*4549Seric 			}
130*4549Seric 			sendto(p, 1, NULL);
131*4549Seric 			if (Errors == 0)
132*4549Seric 			{
133*4549Seric 				message("250", "Recipient ok");
134*4549Seric 				hasmrcp = TRUE;
135*4549Seric 			}
136*4549Seric 			break;
137*4549Seric 
138*4549Seric 		  case CMDDATA:		/* data -- text of mail */
139*4549Seric 			message("354", "Enter mail, end with dot");
140*4549Seric 			collect();
141*4549Seric 			if (Errors == 0)
142*4549Seric 			{
143*4549Seric 				message("250", "Message stored");
144*4549Seric 				hasdata = TRUE;
145*4549Seric 			}
146*4549Seric 			break;
147*4549Seric 
148*4549Seric 		  case CMDDOIT:		/* doit -- actually send everything */
149*4549Seric 			if (!hasmail)
150*4549Seric 				message("503", "Need MAIL command");
151*4549Seric 			else if (!hasmrcp)
152*4549Seric 				message("503", "Need MRCP (recipient)");
153*4549Seric 			else if (!hasdata)
154*4549Seric 				message("503", "No message, use DATA");
155*4549Seric 			else
156*4549Seric 			{
157*4549Seric 				sendall(FALSE);
158*4549Seric 				if (Errors == 0)
159*4549Seric 					message("250", "Sent");
160*4549Seric 			}
161*4549Seric 			break;
162*4549Seric 
163*4549Seric 		  case CMDRSET:		/* rset -- reset state */
164*4549Seric 			message("250", "Reset state");
165*4549Seric 			finis();
166*4549Seric 
167*4549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
168*4549Seric 			sendto(p, 1, NULL);
169*4549Seric 			if (Errors == 0)
170*4549Seric 				message("250", "user ok");
171*4549Seric 			break;
172*4549Seric 
173*4549Seric 		  case CMDHELP:		/* help -- give user info */
174*4549Seric 			message("502", "HELP not implemented");
175*4549Seric 			break;
176*4549Seric 
177*4549Seric 		  case CMDNOOP:		/* noop -- do nothing */
178*4549Seric 			message("200", "OK");
179*4549Seric 			break;
180*4549Seric 
181*4549Seric 		  case CMDQUIT:		/* quit -- leave mail */
182*4549Seric 			message("221", "%s closing connection", HostName);
183*4549Seric 			finis();
184*4549Seric 
185*4549Seric 		  case CMDERROR:	/* unknown command */
186*4549Seric 			message("500", "Command unrecognized");
187*4549Seric 			break;
188*4549Seric 
189*4549Seric 		  default:
190*4549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
191*4549Seric 			break;
192*4549Seric 		}
193*4549Seric 	}
194*4549Seric }
195*4549Seric /*
196*4549Seric **  SKIPWORD -- skip a fixed word.
197*4549Seric **
198*4549Seric **	Parameters:
199*4549Seric **		p -- place to start looking.
200*4549Seric **		w -- word to skip.
201*4549Seric **
202*4549Seric **	Returns:
203*4549Seric **		p following w.
204*4549Seric **		NULL on error.
205*4549Seric **
206*4549Seric **	Side Effects:
207*4549Seric **		clobbers the p data area.
208*4549Seric */
209*4549Seric 
210*4549Seric static char *
211*4549Seric skipword(p, w)
212*4549Seric 	register char *p;
213*4549Seric 	char *w;
214*4549Seric {
215*4549Seric 	register char *q;
216*4549Seric 	extern bool sameword();
217*4549Seric 
218*4549Seric 	/* find beginning of word */
219*4549Seric 	while (isspace(*p))
220*4549Seric 		p++;
221*4549Seric 	q = p;
222*4549Seric 
223*4549Seric 	/* find end of word */
224*4549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
225*4549Seric 		p++;
226*4549Seric 	while (isspace(*p))
227*4549Seric 		*p++ = '\0';
228*4549Seric 	if (*p != ':')
229*4549Seric 	{
230*4549Seric 	  syntax:
231*4549Seric 		message("501", "Syntax error");
232*4549Seric 		Errors++;
233*4549Seric 		return (NULL);
234*4549Seric 	}
235*4549Seric 	*p++ = '\0';
236*4549Seric 	while (isspace(*p))
237*4549Seric 		p++;
238*4549Seric 
239*4549Seric 	/* see if the input word matches desired word */
240*4549Seric 	if (!sameword(q, w))
241*4549Seric 		goto syntax;
242*4549Seric 
243*4549Seric 	return (p);
244*4549Seric }
245