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