1 # include <ctype.h>
2 # include <sysexits.h>
3 # include "sendmail.h"
4 
5 # ifndef SMTP
6 SCCSID(@(#)usersmtp.c	3.27		11/24/82	(no SMTP));
7 # else SMTP
8 
9 SCCSID(@(#)usersmtp.c	3.27		11/24/82);
10 
11 /*
12 **  SMTPINIT -- initialize SMTP.
13 **
14 **	Opens the connection and sends the initial protocol.
15 **
16 **	Parameters:
17 **		m -- mailer to create connection to.
18 **		pvp -- pointer to parameter vector to pass to
19 **			the mailer.
20 **		ctladdr -- controlling address for this mailer.
21 **
22 **	Returns:
23 **		appropriate exit status -- EX_OK on success.
24 **
25 **	Side Effects:
26 **		creates connection and sends initial protocol.
27 */
28 
29 # define REPLYTYPE(r)	((r) / 100)
30 # define REPLYCLASS(r)	(((r) / 10) % 10)
31 
32 static FILE	*SmtpOut;	/* output file */
33 static FILE	*SmtpIn;	/* input file */
34 static int	SmtpPid;	/* pid of mailer */
35 static int	SmtpErrstat;	/* error status if open fails */
36 
37 smtpinit(m, pvp, ctladdr)
38 	struct mailer *m;
39 	char **pvp;
40 	ADDRESS *ctladdr;
41 {
42 	register int r;
43 	char buf[MAXNAME];
44 	extern tick();
45 	extern char *canonname();
46 
47 	/*
48 	**  Open the connection to the mailer.
49 	*/
50 
51 	SmtpIn = SmtpOut = NULL;
52 	SmtpPid = openmailer(m, pvp, ctladdr, TRUE, &SmtpOut, &SmtpIn);
53 	if (SmtpPid < 0)
54 	{
55 		SmtpErrstat = ExitStat;
56 # ifdef DEBUG
57 		if (tTd(18, 1))
58 			printf("smtpinit: cannot open: Errstat %d errno %d\n",
59 			   SmtpErrstat, errno);
60 # endif DEBUG
61 		return (ExitStat);
62 	}
63 
64 	/*
65 	**  Get the greeting message.
66 	**	This should appear spontaneously.
67 	*/
68 
69 	r = reply();
70 	if (r < 0 || REPLYTYPE(r) != 2)
71 		return (EX_TEMPFAIL);
72 
73 	/*
74 	**  Send the HELO command.
75 	**	My mother taught me to always introduce myself.
76 	*/
77 
78 	smtpmessage("HELO %s", HostName);
79 	r = reply();
80 	if (r < 0)
81 		return (EX_TEMPFAIL);
82 	else if (REPLYTYPE(r) == 5)
83 		return (EX_UNAVAILABLE);
84 	else if (REPLYTYPE(r) != 2)
85 		return (EX_TEMPFAIL);
86 
87 	/*
88 	**  If this is expected to be another sendmail, send some internal
89 	**  commands.
90 	*/
91 
92 	if (bitset(M_INTERNAL, m->m_flags))
93 	{
94 		/* tell it to be verbose */
95 		smtpmessage("VERB");
96 		r = reply();
97 		if (r < 0)
98 			return (EX_TEMPFAIL);
99 
100 		/* tell it we will be sending one transaction only */
101 		smtpmessage("ONEX");
102 		r = reply();
103 		if (r < 0)
104 			return (EX_TEMPFAIL);
105 	}
106 
107 	/*
108 	**  Send the MAIL command.
109 	**	Designates the sender.
110 	*/
111 
112 	expand("$g", buf, &buf[sizeof buf - 1], CurEnv);
113 	if (CurEnv->e_from.q_mailer == LocalMailer ||
114 	    !bitset(M_FULLSMTP, m->m_flags))
115 	{
116 		smtpmessage("MAIL From:<%s>", canonname(buf, 1));
117 	}
118 	else
119 	{
120 		smtpmessage("MAIL From:<@%s%c%s>", HostName,
121 			    buf[0] == '@' ? ',' : ':', canonname(buf, 1));
122 	}
123 	r = reply();
124 	if (r < 0 || REPLYTYPE(r) == 4)
125 		return (EX_TEMPFAIL);
126 	else if (r == 250)
127 		return (EX_OK);
128 	else if (r == 552)
129 		return (EX_UNAVAILABLE);
130 	return (EX_PROTOCOL);
131 }
132 /*
133 **  SMTPRCPT -- designate recipient.
134 **
135 **	Parameters:
136 **		to -- address of recipient.
137 **
138 **	Returns:
139 **		exit status corresponding to recipient status.
140 **
141 **	Side Effects:
142 **		Sends the mail via SMTP.
143 */
144 
145 smtprcpt(to)
146 	ADDRESS *to;
147 {
148 	register int r;
149 	extern char *canonname();
150 
151 	if (SmtpPid < 0)
152 		return (SmtpErrstat);
153 
154 	smtpmessage("RCPT To:<%s>", canonname(to->q_user, 2));
155 
156 	r = reply();
157 	if (r < 0 || REPLYTYPE(r) == 4)
158 		return (EX_TEMPFAIL);
159 	else if (REPLYTYPE(r) == 2)
160 		return (EX_OK);
161 	else if (r == 550 || r == 551 || r == 553)
162 		return (EX_NOUSER);
163 	else if (r == 552 || r == 554)
164 		return (EX_UNAVAILABLE);
165 	return (EX_PROTOCOL);
166 }
167 /*
168 **  SMTPFINISH -- finish up sending all the SMTP protocol.
169 **
170 **	Parameters:
171 **		m -- mailer being sent to.
172 **		e -- the envelope for this message.
173 **
174 **	Returns:
175 **		exit status corresponding to DATA command.
176 **
177 **	Side Effects:
178 **		none.
179 */
180 
181 smtpfinish(m, e)
182 	struct mailer *m;
183 	register ENVELOPE *e;
184 {
185 	register int r;
186 
187 	if (SmtpPid < 0)
188 		return (SmtpErrstat);
189 
190 	/*
191 	**  Send the data.
192 	**	Dot hiding is done here.
193 	*/
194 
195 	smtpmessage("DATA");
196 	r = reply();
197 	if (r < 0 || REPLYTYPE(r) == 4)
198 		return (EX_TEMPFAIL);
199 	else if (r == 554)
200 		return (EX_UNAVAILABLE);
201 	else if (r != 354)
202 		return (EX_PROTOCOL);
203 	(*e->e_puthdr)(SmtpOut, m, CurEnv);
204 	fprintf(SmtpOut, "\n");
205 	(*e->e_putbody)(SmtpOut, m, TRUE);
206 	smtpmessage(".");
207 	r = reply();
208 	if (r < 0 || REPLYTYPE(r) == 4)
209 		return (EX_TEMPFAIL);
210 	else if (r == 250)
211 		return (EX_OK);
212 	else if (r == 552 || r == 554)
213 		return (EX_UNAVAILABLE);
214 	return (EX_PROTOCOL);
215 }
216 /*
217 **  SMTPQUIT -- close the SMTP connection.
218 **
219 **	Parameters:
220 **		name -- name of mailer we are quitting.
221 **		showresp -- if set, give a response message.
222 **
223 **	Returns:
224 **		none.
225 **
226 **	Side Effects:
227 **		sends the final protocol and closes the connection.
228 */
229 
230 smtpquit(name, showresp)
231 	char *name;
232 	bool showresp;
233 {
234 	register int i;
235 
236 	if (SmtpPid < 0)
237 		return;
238 	smtpmessage("QUIT");
239 	(void) reply();
240 	(void) fclose(SmtpIn);
241 	(void) fclose(SmtpOut);
242 	i = endmailer(SmtpPid, name);
243 	if (showresp)
244 		giveresponse(i, TRUE, LocalMailer);
245 }
246 /*
247 **  REPLY -- read arpanet reply
248 **
249 **	Parameters:
250 **		none.
251 **
252 **	Returns:
253 **		reply code it reads.
254 **
255 **	Side Effects:
256 **		flushes the mail file.
257 */
258 
259 reply()
260 {
261 	(void) fflush(SmtpOut);
262 
263 	if (tTd(18, 1))
264 		printf("reply\n");
265 
266 	/*
267 	**  Read the input line, being careful not to hang.
268 	*/
269 
270 	for (;;)
271 	{
272 		char buf[MAXLINE];
273 		register int r;
274 		register char *p;
275 
276 		/* actually do the read */
277 		if (Xscript != NULL)
278 			(void) fflush(Xscript);		/* for debugging */
279 		p = sfgets(buf, sizeof buf, SmtpIn);
280 		if (p == NULL)
281 			return (-1);
282 		fixcrlf(buf, TRUE);
283 
284 		/* log the input in the transcript for future error returns */
285 		if (Verbose && !HoldErrs)
286 			nmessage(Arpa_Info, "%s", buf);
287 		if (Xscript != NULL)
288 			fprintf(Xscript, "%s\n", buf);
289 
290 		/* if continuation is required, we can go on */
291 		if (buf[3] == '-' || !isdigit(buf[0]))
292 			continue;
293 
294 		/* decode the reply code */
295 		r = atoi(buf);
296 
297 		/* extra semantics: 0xx codes are "informational" */
298 		if (r < 100)
299 			continue;
300 
301 		return (r);
302 	}
303 }
304 /*
305 **  SMTPMESSAGE -- send message to server
306 **
307 **	Parameters:
308 **		f -- format
309 **		a, b, c -- parameters
310 **
311 **	Returns:
312 **		none.
313 **
314 **	Side Effects:
315 **		writes message to SmtpOut.
316 */
317 
318 /*VARARGS1*/
319 smtpmessage(f, a, b, c)
320 	char *f;
321 {
322 	char buf[100];
323 
324 	(void) sprintf(buf, f, a, b, c);
325 	if (tTd(18, 1) || (Verbose && !HoldErrs))
326 		nmessage(Arpa_Info, ">>> %s", buf);
327 	if (Xscript != NULL)
328 		fprintf(Xscript, ">>> %s\n", buf);
329 	fprintf(SmtpOut, "%s\r\n", buf);
330 }
331 
332 # endif SMTP
333