1 # include <ctype.h>
2 # include <signal.h>
3 # include <sysexits.h>
4 # include "sendmail.h"
5 
6 # ifndef SMTP
7 SCCSID(@(#)usersmtp.c	3.15		08/08/82	(no SMTP));
8 # else SMTP
9 
10 SCCSID(@(#)usersmtp.c	3.15		08/08/82);
11 
12 /*
13 **  SMTPINIT -- initialize SMTP.
14 **
15 **	Opens the connection and sends the initial protocol.
16 **
17 **	Parameters:
18 **		m -- mailer to create connection to.
19 **		pvp -- pointer to parameter vector to pass to
20 **			the mailer.
21 **		ctladdr -- controlling address for this mailer.
22 **
23 **	Returns:
24 **		appropriate exit status -- EX_OK on success.
25 **
26 **	Side Effects:
27 **		creates connection and sends initial protocol.
28 */
29 
30 # define REPLYTYPE(r)	((r) / 100)
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 
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 	(void) signal(SIGALRM, tick);
63 
64 	/*
65 	**  Get the greeting message.
66 	**	This should appear spontaneously.
67 	*/
68 
69 	r = reply();
70 	if (REPLYTYPE(r) != 2)
71 		return (EX_TEMPFAIL);
72 
73 	/*
74 	**  Send the HELO command.
75 	**	My mother taught me to always introduce myself, even
76 	**	if it is useless.
77 	*/
78 
79 	smtpmessage("HELO %s", HostName);
80 	r = reply();
81 	if (REPLYTYPE(r) == 5)
82 		return (EX_UNAVAILABLE);
83 	if (REPLYTYPE(r) != 2)
84 		return (EX_TEMPFAIL);
85 
86 	/*
87 	**  Send the MAIL command.
88 	**	Designates the sender.
89 	*/
90 
91 	expand("$g", buf, &buf[sizeof buf - 1], CurEnv);
92 	smtpmessage("MAIL From:<%s>", buf);
93 	r = reply();
94 	if (REPLYTYPE(r) == 4)
95 		return (EX_TEMPFAIL);
96 	if (r != 250)
97 		return (EX_SOFTWARE);
98 	return (EX_OK);
99 }
100 /*
101 **  SMTPRCPT -- designate recipient.
102 **
103 **	Parameters:
104 **		to -- address of recipient.
105 **
106 **	Returns:
107 **		exit status corresponding to recipient status.
108 **
109 **	Side Effects:
110 **		Sends the mail via SMTP.
111 */
112 
113 smtprcpt(to)
114 	ADDRESS *to;
115 {
116 	register int r;
117 
118 	if (SmtpPid < 0)
119 		return (SmtpErrstat);
120 
121 	smtpmessage("RCPT To:<%s>", to->q_user);
122 
123 	r = reply();
124 	if (REPLYTYPE(r) == 4)
125 		return (EX_TEMPFAIL);
126 	if (r != 250)
127 		return (EX_NOUSER);
128 
129 	return (EX_OK);
130 }
131 /*
132 **  SMTPFINISH -- finish up sending all the SMTP protocol.
133 **
134 **	Parameters:
135 **		m -- mailer being sent to.
136 **		e -- the envelope for this message.
137 **
138 **	Returns:
139 **		exit status corresponding to DATA command.
140 **
141 **	Side Effects:
142 **		none.
143 */
144 
145 smtpfinish(m, e)
146 	struct mailer *m;
147 	register ENVELOPE *e;
148 {
149 	register int r;
150 
151 	if (SmtpPid < 0)
152 		return (SmtpErrstat);
153 
154 	/*
155 	**  Send the data.
156 	**	Dot hiding is done here.
157 	*/
158 
159 	smtpmessage("DATA");
160 	r = reply();
161 	if (REPLYTYPE(r) == 4)
162 		return (EX_TEMPFAIL);
163 	if (r != 354)
164 		return (EX_SOFTWARE);
165 	(*e->e_puthdr)(SmtpOut, m, CurEnv);
166 	fprintf(SmtpOut, "\n");
167 	(*e->e_putbody)(SmtpOut, m, TRUE);
168 	smtpmessage(".");
169 	r = reply();
170 	if (REPLYTYPE(r) == 4)
171 		return (EX_TEMPFAIL);
172 	if (r != 250)
173 		return (EX_SOFTWARE);
174 	return (EX_OK);
175 }
176 /*
177 **  SMTPQUIT -- close the SMTP connection.
178 **
179 **	Parameters:
180 **		name -- name of mailer we are quitting.
181 **		showresp -- if set, give a response message.
182 **
183 **	Returns:
184 **		none.
185 **
186 **	Side Effects:
187 **		sends the final protocol and closes the connection.
188 */
189 
190 smtpquit(name, showresp)
191 	char *name;
192 	bool showresp;
193 {
194 	register int i;
195 
196 	if (SmtpPid < 0)
197 		return;
198 	smtpmessage("QUIT");
199 	(void) reply();
200 	(void) fclose(SmtpIn);
201 	(void) fclose(SmtpOut);
202 	i = endmailer(SmtpPid, name);
203 	if (showresp)
204 		giveresponse(i, TRUE, LocalMailer);
205 }
206 /*
207 **  REPLY -- read arpanet reply
208 **
209 **	Parameters:
210 **		none.
211 **
212 **	Returns:
213 **		reply code it reads.
214 **
215 **	Side Effects:
216 **		flushes the mail file.
217 */
218 
219 reply()
220 {
221 	(void) fflush(SmtpOut);
222 
223 	if (tTd(18, 1))
224 		printf("reply\n");
225 
226 	/*
227 	**  Read the input line, being careful not to hang.
228 	*/
229 
230 	for (;;)
231 	{
232 		char buf[MAXLINE];
233 		register int r;
234 		register char *p;
235 
236 		/* arrange to time out the read */
237 		(void) fflush(Xscript);			/* for debugging */
238 		if (setjmp(TickFrame) != 0)
239 			return (-1);
240 		(void) alarm(ReadTimeout);
241 
242 		/* actually do the read */
243 		p = fgets(buf, sizeof buf, SmtpIn);
244 
245 		/* clean up timeout and check for errors */
246 		(void) alarm(0);
247 		if (p == NULL)
248 			return (-1);
249 
250 		/* log the input in the transcript for future error returns */
251 		if (Verbose && !HoldErrs)
252 			fputs(buf, stdout);
253 		fputs(buf, Xscript);
254 
255 		/* if continuation is required, we can go on */
256 		if (buf[3] == '-' || !isdigit(buf[0]))
257 			continue;
258 
259 		/* decode the reply code */
260 		r = atoi(buf);
261 
262 		/* extra semantics: 0xx codes are "informational" */
263 		if (r < 100)
264 			continue;
265 
266 		return (r);
267 	}
268 }
269 /*
270 **  SMTPMESSAGE -- send message to server
271 **
272 **	Parameters:
273 **		f -- format
274 **		a, b, c -- parameters
275 **
276 **	Returns:
277 **		none.
278 **
279 **	Side Effects:
280 **		writes message to SmtpOut.
281 */
282 
283 /*VARARGS1*/
284 smtpmessage(f, a, b, c)
285 	char *f;
286 {
287 	char buf[100];
288 
289 	(void) sprintf(buf, f, a, b, c);
290 	if (tTd(18, 1) || (Verbose && !HoldErrs))
291 		printf(">>> %s\n", buf);
292 	fprintf(Xscript, ">>> %s\n", buf);
293 	fprintf(SmtpOut, "%s\r\n", buf);
294 }
295 
296 # endif SMTP
297