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