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