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