Commit | Line | Data |
---|---|---|
b2a81223 | 1 | /* |
dc45ba8c | 2 | * Copyright (c) 1983 Eric P. Allman |
24634489 KB |
3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
bee79b64 | 5 | * |
0d77f9d8 | 6 | * %sccs.include.redist.c% |
bee79b64 | 7 | */ |
b2a81223 | 8 | |
e6b0a75b | 9 | # include "sendmail.h" |
d2eb2478 | 10 | |
bee79b64 KB |
11 | #ifndef lint |
12 | #ifdef SMTP | |
24634489 | 13 | static char sccsid[] = "@(#)usersmtp.c 8.1 (Berkeley) %G% (with SMTP)"; |
bee79b64 | 14 | #else |
24634489 | 15 | static char sccsid[] = "@(#)usersmtp.c 8.1 (Berkeley) %G% (without SMTP)"; |
bee79b64 KB |
16 | #endif |
17 | #endif /* not lint */ | |
80482eb5 | 18 | |
bee79b64 KB |
19 | # include <sysexits.h> |
20 | # include <errno.h> | |
80482eb5 | 21 | |
bee79b64 | 22 | # ifdef SMTP |
d2eb2478 EA |
23 | |
24 | /* | |
80482eb5 EA |
25 | ** USERSMTP -- run SMTP protocol from the user end. |
26 | ** | |
27 | ** This protocol is described in RFC821. | |
28 | */ | |
29 | ||
30 | #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ | |
31 | #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ | |
32 | #define SMTPCLOSING 421 /* "Service Shutting Down" */ | |
33 | ||
d7dbe85b | 34 | char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ |
d0729491 | 35 | char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ |
46f6ec52 | 36 | char SmtpError[MAXLINE] = ""; /* save failure error messages */ |
d0729491 | 37 | int SmtpPid; /* pid of mailer */ |
16133a1c EA |
38 | |
39 | #ifdef __STDC__ | |
40 | extern smtpmessage(char *f, MAILER *m, MCI *mci, ...); | |
41 | #endif | |
80482eb5 | 42 | \f/* |
e6b0a75b | 43 | ** SMTPINIT -- initialize SMTP. |
d2eb2478 | 44 | ** |
e6b0a75b | 45 | ** Opens the connection and sends the initial protocol. |
d2eb2478 EA |
46 | ** |
47 | ** Parameters: | |
e6b0a75b EA |
48 | ** m -- mailer to create connection to. |
49 | ** pvp -- pointer to parameter vector to pass to | |
50 | ** the mailer. | |
d2eb2478 EA |
51 | ** |
52 | ** Returns: | |
f2e44ded | 53 | ** none. |
d2eb2478 EA |
54 | ** |
55 | ** Side Effects: | |
e6b0a75b | 56 | ** creates connection and sends initial protocol. |
d2eb2478 EA |
57 | */ |
58 | ||
f2e44ded | 59 | smtpinit(m, mci, e) |
e6b0a75b | 60 | struct mailer *m; |
f2e44ded | 61 | register MCI *mci; |
e62e1144 | 62 | ENVELOPE *e; |
d2eb2478 | 63 | { |
e6b0a75b | 64 | register int r; |
a9bac7a9 | 65 | register char *p; |
77c24e97 | 66 | extern void esmtp_check(); |
3001ca78 | 67 | extern void helo_options(); |
d2eb2478 | 68 | |
474bc899 EA |
69 | if (tTd(17, 1)) |
70 | { | |
71 | printf("smtpinit "); | |
72 | mci_dump(mci); | |
73 | } | |
74 | ||
e6b0a75b EA |
75 | /* |
76 | ** Open the connection to the mailer. | |
77 | */ | |
d2eb2478 | 78 | |
46f6ec52 | 79 | SmtpError[0] = '\0'; |
474bc899 | 80 | CurHostName = mci->mci_host; /* XXX UGLY XXX */ |
f2e44ded | 81 | switch (mci->mci_state) |
1ea752a1 | 82 | { |
f2e44ded EA |
83 | case MCIS_ACTIVE: |
84 | /* need to clear old information */ | |
85 | smtprset(m, mci, e); | |
263c5860 | 86 | /* fall through */ |
46f6ec52 | 87 | |
f2e44ded EA |
88 | case MCIS_OPEN: |
89 | return; | |
90 | ||
91 | case MCIS_ERROR: | |
92 | case MCIS_SSD: | |
93 | /* shouldn't happen */ | |
94 | smtpquit(m, mci, e); | |
263c5860 | 95 | /* fall through */ |
f2e44ded EA |
96 | |
97 | case MCIS_CLOSED: | |
b6edea3d | 98 | syserr("451 smtpinit: state CLOSED"); |
f2e44ded EA |
99 | return; |
100 | ||
101 | case MCIS_OPENING: | |
102 | break; | |
1ea752a1 | 103 | } |
d2eb2478 | 104 | |
f2e44ded EA |
105 | mci->mci_state = MCIS_OPENING; |
106 | ||
e6b0a75b EA |
107 | /* |
108 | ** Get the greeting message. | |
057a9c5d | 109 | ** This should appear spontaneously. Give it five minutes to |
e4581b86 | 110 | ** happen. |
e6b0a75b | 111 | */ |
3c6123ce | 112 | |
8e948497 | 113 | SmtpPhase = mci->mci_phase = "client greeting"; |
e62e1144 | 114 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
77c24e97 | 115 | r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check); |
3ff6d543 | 116 | if (r < 0 || REPLYTYPE(r) != 2) |
07cb6633 | 117 | goto tempfail1; |
42281a7d | 118 | |
4a4ebe09 EA |
119 | /* |
120 | ** Send the HELO command. | |
4672197a | 121 | ** My mother taught me to always introduce myself. |
4a4ebe09 EA |
122 | */ |
123 | ||
3001ca78 EA |
124 | if (bitnset(M_ESMTP, m->m_flags)) |
125 | mci->mci_flags |= MCIF_ESMTP; | |
126 | ||
127 | tryhelo: | |
128 | if (bitset(MCIF_ESMTP, mci->mci_flags)) | |
129 | { | |
130 | smtpmessage("EHLO %s", m, mci, MyHostName); | |
8e948497 | 131 | SmtpPhase = mci->mci_phase = "client EHLO"; |
3001ca78 EA |
132 | } |
133 | else | |
134 | { | |
135 | smtpmessage("HELO %s", m, mci, MyHostName); | |
8e948497 | 136 | SmtpPhase = mci->mci_phase = "client HELO"; |
3001ca78 | 137 | } |
e62e1144 | 138 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
3001ca78 | 139 | r = reply(m, mci, e, TimeOuts.to_helo, helo_options); |
3ff6d543 | 140 | if (r < 0) |
07cb6633 | 141 | goto tempfail1; |
3ff6d543 | 142 | else if (REPLYTYPE(r) == 5) |
3001ca78 EA |
143 | { |
144 | if (bitset(MCIF_ESMTP, mci->mci_flags)) | |
145 | { | |
146 | /* try old SMTP instead */ | |
147 | mci->mci_flags &= ~MCIF_ESMTP; | |
148 | goto tryhelo; | |
149 | } | |
057a9c5d | 150 | goto unavailable; |
3001ca78 | 151 | } |
4672197a | 152 | else if (REPLYTYPE(r) != 2) |
07cb6633 | 153 | goto tempfail1; |
4a4ebe09 | 154 | |
a9bac7a9 EA |
155 | /* |
156 | ** Check to see if we actually ended up talking to ourself. | |
157 | ** This means we didn't know about an alias or MX, or we managed | |
158 | ** to connect to an echo server. | |
159 | */ | |
160 | ||
f4900dab | 161 | p = strchr(&SmtpReplyBuffer[4], ' '); |
a9bac7a9 | 162 | if (p != NULL) |
a3934270 | 163 | *p = '\0'; |
f4900dab | 164 | if (strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0) |
a9bac7a9 EA |
165 | { |
166 | syserr("553 %s config error: mail loops back to myself", | |
167 | MyHostName); | |
168 | mci->mci_exitstat = EX_CONFIG; | |
169 | mci->mci_errno = 0; | |
170 | smtpquit(m, mci, e); | |
171 | return; | |
172 | } | |
173 | ||
8fe4fb9b EA |
174 | /* |
175 | ** If this is expected to be another sendmail, send some internal | |
176 | ** commands. | |
177 | */ | |
178 | ||
1dbda134 | 179 | if (bitnset(M_INTERNAL, m->m_flags)) |
8fe4fb9b EA |
180 | { |
181 | /* tell it to be verbose */ | |
e62e1144 | 182 | smtpmessage("VERB", m, mci); |
3001ca78 | 183 | r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); |
8fe4fb9b | 184 | if (r < 0) |
07cb6633 | 185 | goto tempfail2; |
8fe4fb9b EA |
186 | } |
187 | ||
e62e1144 | 188 | mci->mci_state = MCIS_OPEN; |
f2e44ded | 189 | return; |
e62e1144 EA |
190 | |
191 | tempfail1: | |
192 | tempfail2: | |
193 | mci->mci_exitstat = EX_TEMPFAIL; | |
474bc899 EA |
194 | if (mci->mci_errno == 0) |
195 | mci->mci_errno = errno; | |
196 | if (mci->mci_state != MCIS_CLOSED) | |
197 | smtpquit(m, mci, e); | |
f2e44ded | 198 | return; |
e62e1144 EA |
199 | |
200 | unavailable: | |
201 | mci->mci_exitstat = EX_UNAVAILABLE; | |
202 | mci->mci_errno = errno; | |
203 | smtpquit(m, mci, e); | |
f2e44ded | 204 | return; |
e62e1144 | 205 | } |
3001ca78 | 206 | \f/* |
77c24e97 EA |
207 | ** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol |
208 | ** | |
209 | ** | |
210 | ** Parameters: | |
211 | ** line -- the response line. | |
212 | ** m -- the mailer. | |
213 | ** mci -- the mailer connection info. | |
214 | ** e -- the envelope. | |
215 | ** | |
216 | ** Returns: | |
217 | ** none. | |
218 | */ | |
219 | ||
220 | void | |
221 | esmtp_check(line, m, mci, e) | |
222 | char *line; | |
223 | MAILER *m; | |
224 | register MCI *mci; | |
225 | ENVELOPE *e; | |
226 | { | |
227 | if (strlen(line) < 5) | |
228 | return; | |
229 | line += 4; | |
230 | if (strncmp(line, "ESMTP ", 6) == 0) | |
231 | mci->mci_flags |= MCIF_ESMTP; | |
232 | } | |
233 | \f/* | |
3001ca78 EA |
234 | ** HELO_OPTIONS -- process the options on a HELO line. |
235 | ** | |
236 | ** Parameters: | |
237 | ** line -- the response line. | |
238 | ** m -- the mailer. | |
239 | ** mci -- the mailer connection info. | |
240 | ** e -- the envelope. | |
241 | ** | |
242 | ** Returns: | |
243 | ** none. | |
244 | */ | |
245 | ||
246 | void | |
247 | helo_options(line, m, mci, e) | |
248 | char *line; | |
249 | MAILER *m; | |
250 | register MCI *mci; | |
251 | ENVELOPE *e; | |
252 | { | |
253 | register char *p; | |
254 | ||
255 | if (strlen(line) < 5) | |
256 | return; | |
257 | line += 4; | |
258 | p = strchr(line, ' '); | |
259 | if (p != NULL) | |
260 | *p++ = '\0'; | |
261 | if (strcasecmp(line, "size") == 0) | |
262 | { | |
263 | mci->mci_flags |= MCIF_SIZE; | |
264 | if (p != NULL) | |
265 | mci->mci_maxsize = atol(p); | |
266 | } | |
267 | else if (strcasecmp(line, "8bitmime") == 0) | |
268 | mci->mci_flags |= MCIF_8BITMIME; | |
269 | else if (strcasecmp(line, "expn") == 0) | |
270 | mci->mci_flags |= MCIF_EXPN; | |
271 | } | |
272 | \f/* | |
273 | ** SMTPMAILFROM -- send MAIL command | |
274 | ** | |
275 | ** Parameters: | |
276 | ** m -- the mailer. | |
277 | ** mci -- the mailer connection structure. | |
278 | ** e -- the envelope (including the sender to specify). | |
279 | */ | |
e62e1144 EA |
280 | |
281 | smtpmailfrom(m, mci, e) | |
282 | struct mailer *m; | |
f2e44ded | 283 | MCI *mci; |
e62e1144 EA |
284 | ENVELOPE *e; |
285 | { | |
286 | int r; | |
287 | char buf[MAXNAME]; | |
3001ca78 | 288 | char optbuf[MAXLINE]; |
e62e1144 | 289 | |
322eceee EA |
290 | if (tTd(17, 2)) |
291 | printf("smtpmailfrom: CurHost=%s\n", CurHostName); | |
292 | ||
3001ca78 EA |
293 | /* set up appropriate options to include */ |
294 | if (bitset(MCIF_SIZE, mci->mci_flags)) | |
295 | sprintf(optbuf, " SIZE=%ld", e->e_msgsize); | |
296 | else | |
297 | strcpy(optbuf, ""); | |
298 | ||
7d7fdf93 EA |
299 | /* |
300 | ** Send the HOPS command. | |
301 | ** This is non-standard and may give an "unknown command". | |
302 | ** This is not an error. | |
303 | ** It can give a "bad hop count" error if the hop | |
304 | ** count is exceeded. | |
305 | */ | |
306 | ||
e6b0a75b EA |
307 | /* |
308 | ** Send the MAIL command. | |
309 | ** Designates the sender. | |
310 | */ | |
42281a7d | 311 | |
e62e1144 EA |
312 | mci->mci_state = MCIS_ACTIVE; |
313 | ||
2cd2111f EA |
314 | if (bitset(EF_RESPONSE, e->e_flags) && |
315 | !bitnset(M_NO_NULL_FROM, m->m_flags)) | |
bc854e30 EA |
316 | (void) strcpy(buf, ""); |
317 | else | |
318 | expand("\201g", buf, &buf[sizeof buf - 1], e); | |
e62e1144 | 319 | if (e->e_from.q_mailer == LocalMailer || |
1dbda134 | 320 | !bitnset(M_FROMPATH, m->m_flags)) |
6abb7b86 | 321 | { |
3001ca78 | 322 | smtpmessage("MAIL From:<%s>%s", m, mci, buf, optbuf); |
6abb7b86 EA |
323 | } |
324 | else | |
325 | { | |
3001ca78 EA |
326 | smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, |
327 | buf[0] == '@' ? ',' : ':', buf, optbuf); | |
6abb7b86 | 328 | } |
8e948497 | 329 | SmtpPhase = mci->mci_phase = "client MAIL"; |
e62e1144 | 330 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
3001ca78 | 331 | r = reply(m, mci, e, TimeOuts.to_mail, NULL); |
3ff6d543 | 332 | if (r < 0 || REPLYTYPE(r) == 4) |
e62e1144 EA |
333 | { |
334 | mci->mci_exitstat = EX_TEMPFAIL; | |
335 | mci->mci_errno = errno; | |
336 | smtpquit(m, mci, e); | |
e62e1144 EA |
337 | return EX_TEMPFAIL; |
338 | } | |
4672197a | 339 | else if (r == 250) |
e62e1144 EA |
340 | { |
341 | mci->mci_exitstat = EX_OK; | |
342 | return EX_OK; | |
343 | } | |
4672197a | 344 | else if (r == 552) |
e62e1144 EA |
345 | { |
346 | /* signal service unavailable */ | |
347 | mci->mci_exitstat = EX_UNAVAILABLE; | |
348 | smtpquit(m, mci, e); | |
e62e1144 EA |
349 | return EX_UNAVAILABLE; |
350 | } | |
057a9c5d | 351 | |
51d9cc47 | 352 | #ifdef LOG |
68f7099c | 353 | if (LogLevel > 1) |
51d9cc47 EA |
354 | { |
355 | syslog(LOG_CRIT, "%s: SMTP MAIL protocol error: %s", | |
356 | e->e_id, SmtpReplyBuffer); | |
357 | } | |
358 | #endif | |
359 | ||
057a9c5d | 360 | /* protocol error -- close up */ |
e62e1144 EA |
361 | smtpquit(m, mci, e); |
362 | mci->mci_exitstat = EX_PROTOCOL; | |
e62e1144 | 363 | return EX_PROTOCOL; |
d2eb2478 EA |
364 | } |
365 | \f/* | |
4a4ebe09 | 366 | ** SMTPRCPT -- designate recipient. |
3c6123ce EA |
367 | ** |
368 | ** Parameters: | |
e6b0a75b | 369 | ** to -- address of recipient. |
4db45bf1 | 370 | ** m -- the mailer we are sending to. |
474bc899 EA |
371 | ** mci -- the connection info for this transaction. |
372 | ** e -- the envelope for this transaction. | |
3c6123ce EA |
373 | ** |
374 | ** Returns: | |
e6b0a75b | 375 | ** exit status corresponding to recipient status. |
3c6123ce EA |
376 | ** |
377 | ** Side Effects: | |
e6b0a75b | 378 | ** Sends the mail via SMTP. |
3c6123ce EA |
379 | */ |
380 | ||
e62e1144 | 381 | smtprcpt(to, m, mci, e) |
e6b0a75b | 382 | ADDRESS *to; |
4db45bf1 | 383 | register MAILER *m; |
f2e44ded | 384 | MCI *mci; |
e62e1144 | 385 | ENVELOPE *e; |
3c6123ce EA |
386 | { |
387 | register int r; | |
388 | ||
e62e1144 | 389 | smtpmessage("RCPT To:<%s>", m, mci, to->q_user); |
e6b0a75b | 390 | |
8e948497 | 391 | SmtpPhase = mci->mci_phase = "client RCPT"; |
e62e1144 | 392 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
3001ca78 | 393 | r = reply(m, mci, e, TimeOuts.to_rcpt, NULL); |
3ff6d543 | 394 | if (r < 0 || REPLYTYPE(r) == 4) |
e6b0a75b | 395 | return (EX_TEMPFAIL); |
4672197a EA |
396 | else if (REPLYTYPE(r) == 2) |
397 | return (EX_OK); | |
977ccbaf EA |
398 | else if (r == 550 || r == 551 || r == 553) |
399 | return (EX_NOUSER); | |
400 | else if (r == 552 || r == 554) | |
401 | return (EX_UNAVAILABLE); | |
51d9cc47 EA |
402 | |
403 | #ifdef LOG | |
68f7099c | 404 | if (LogLevel > 1) |
51d9cc47 EA |
405 | { |
406 | syslog(LOG_CRIT, "%s: SMTP RCPT protocol error: %s", | |
407 | e->e_id, SmtpReplyBuffer); | |
408 | } | |
409 | #endif | |
410 | ||
977ccbaf | 411 | return (EX_PROTOCOL); |
3c6123ce EA |
412 | } |
413 | \f/* | |
4db45bf1 | 414 | ** SMTPDATA -- send the data and clean up the transaction. |
d2eb2478 EA |
415 | ** |
416 | ** Parameters: | |
e6b0a75b | 417 | ** m -- mailer being sent to. |
dd1fe05b | 418 | ** e -- the envelope for this message. |
d2eb2478 EA |
419 | ** |
420 | ** Returns: | |
4a4ebe09 | 421 | ** exit status corresponding to DATA command. |
d2eb2478 EA |
422 | ** |
423 | ** Side Effects: | |
e6b0a75b | 424 | ** none. |
d2eb2478 EA |
425 | */ |
426 | ||
06771186 | 427 | smtpdata(m, mci, e) |
e6b0a75b | 428 | struct mailer *m; |
f2e44ded | 429 | register MCI *mci; |
dd1fe05b | 430 | register ENVELOPE *e; |
d2eb2478 EA |
431 | { |
432 | register int r; | |
d2eb2478 | 433 | |
3c6123ce EA |
434 | /* |
435 | ** Send the data. | |
4db45bf1 EA |
436 | ** First send the command and check that it is ok. |
437 | ** Then send the data. | |
438 | ** Follow it up with a dot to terminate. | |
439 | ** Finally get the results of the transaction. | |
3c6123ce EA |
440 | */ |
441 | ||
4db45bf1 | 442 | /* send the command and check ok to proceed */ |
e62e1144 | 443 | smtpmessage("DATA", m, mci); |
8e948497 | 444 | SmtpPhase = mci->mci_phase = "client DATA 354"; |
e62e1144 | 445 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
3001ca78 | 446 | r = reply(m, mci, e, TimeOuts.to_datainit, NULL); |
3ff6d543 | 447 | if (r < 0 || REPLYTYPE(r) == 4) |
c6f2ede6 EA |
448 | { |
449 | smtpquit(m, mci, e); | |
3c6123ce | 450 | return (EX_TEMPFAIL); |
c6f2ede6 | 451 | } |
4672197a | 452 | else if (r == 554) |
c6f2ede6 EA |
453 | { |
454 | smtprset(m, mci, e); | |
4672197a | 455 | return (EX_UNAVAILABLE); |
c6f2ede6 | 456 | } |
4672197a | 457 | else if (r != 354) |
c6f2ede6 | 458 | { |
51d9cc47 | 459 | #ifdef LOG |
68f7099c | 460 | if (LogLevel > 1) |
51d9cc47 EA |
461 | { |
462 | syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s", | |
463 | e->e_id, SmtpReplyBuffer); | |
464 | } | |
465 | #endif | |
c6f2ede6 | 466 | smtprset(m, mci, e); |
977ccbaf | 467 | return (EX_PROTOCOL); |
c6f2ede6 | 468 | } |
4db45bf1 EA |
469 | |
470 | /* now output the actual message */ | |
e62e1144 | 471 | (*e->e_puthdr)(mci->mci_out, m, e); |
06771186 | 472 | putline("\n", mci->mci_out, m); |
2f6a8a78 | 473 | (*e->e_putbody)(mci->mci_out, m, e, NULL); |
4db45bf1 EA |
474 | |
475 | /* terminate the message */ | |
06771186 | 476 | fprintf(mci->mci_out, ".%s", m->m_eol); |
dc2cd20f | 477 | if (Verbose) |
b6edea3d | 478 | nmessage(">>> ."); |
4db45bf1 EA |
479 | |
480 | /* check for the results of the transaction */ | |
8e948497 | 481 | SmtpPhase = mci->mci_phase = "client DATA 250"; |
e62e1144 | 482 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
3001ca78 | 483 | r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); |
e62e1144 | 484 | if (r < 0) |
c6f2ede6 EA |
485 | { |
486 | smtpquit(m, mci, e); | |
e62e1144 | 487 | return (EX_TEMPFAIL); |
c6f2ede6 | 488 | } |
e62e1144 | 489 | mci->mci_state = MCIS_OPEN; |
614b4258 | 490 | e->e_statmsg = newstr(&SmtpReplyBuffer[4]); |
e62e1144 | 491 | if (REPLYTYPE(r) == 4) |
3c6123ce | 492 | return (EX_TEMPFAIL); |
4672197a EA |
493 | else if (r == 250) |
494 | return (EX_OK); | |
495 | else if (r == 552 || r == 554) | |
496 | return (EX_UNAVAILABLE); | |
51d9cc47 | 497 | #ifdef LOG |
68f7099c | 498 | if (LogLevel > 1) |
51d9cc47 EA |
499 | { |
500 | syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s", | |
501 | e->e_id, SmtpReplyBuffer); | |
502 | } | |
503 | #endif | |
977ccbaf | 504 | return (EX_PROTOCOL); |
d2eb2478 EA |
505 | } |
506 | \f/* | |
e6b0a75b EA |
507 | ** SMTPQUIT -- close the SMTP connection. |
508 | ** | |
509 | ** Parameters: | |
e009f4f4 | 510 | ** m -- a pointer to the mailer. |
e6b0a75b EA |
511 | ** |
512 | ** Returns: | |
513 | ** none. | |
514 | ** | |
515 | ** Side Effects: | |
516 | ** sends the final protocol and closes the connection. | |
517 | */ | |
518 | ||
e62e1144 | 519 | smtpquit(m, mci, e) |
06771186 | 520 | register MAILER *m; |
f2e44ded | 521 | register MCI *mci; |
e62e1144 | 522 | ENVELOPE *e; |
e6b0a75b | 523 | { |
80482eb5 | 524 | int i; |
e6b0a75b | 525 | |
f2e44ded | 526 | /* send the quit message if we haven't gotten I/O error */ |
e62e1144 | 527 | if (mci->mci_state != MCIS_ERROR) |
044ab67a | 528 | { |
8e948497 | 529 | SmtpPhase = "client QUIT"; |
e62e1144 | 530 | smtpmessage("QUIT", m, mci); |
3001ca78 | 531 | (void) reply(m, mci, e, TimeOuts.to_quit, NULL); |
06771186 | 532 | if (mci->mci_state == MCIS_CLOSED) |
11957f11 | 533 | return; |
80482eb5 EA |
534 | } |
535 | ||
2ae0e0ed | 536 | /* now actually close the connection and pick up the zombie */ |
ffc1c1a0 | 537 | i = endmailer(mci, e, m->m_argv); |
80482eb5 | 538 | if (i != EX_OK) |
b6edea3d | 539 | syserr("451 smtpquit %s: stat %d", m->m_argv[0], i); |
e6b0a75b EA |
540 | } |
541 | \f/* | |
f2e44ded EA |
542 | ** SMTPRSET -- send a RSET (reset) command |
543 | */ | |
544 | ||
545 | smtprset(m, mci, e) | |
546 | register MAILER *m; | |
547 | register MCI *mci; | |
548 | ENVELOPE *e; | |
549 | { | |
550 | int r; | |
551 | ||
8e948497 | 552 | SmtpPhase = "client RSET"; |
f2e44ded | 553 | smtpmessage("RSET", m, mci); |
3001ca78 | 554 | r = reply(m, mci, e, TimeOuts.to_rset, NULL); |
263c5860 EA |
555 | if (r < 0) |
556 | mci->mci_state = MCIS_ERROR; | |
f2e44ded | 557 | else if (REPLYTYPE(r) == 2) |
263c5860 EA |
558 | { |
559 | mci->mci_state = MCIS_OPEN; | |
560 | return; | |
561 | } | |
562 | smtpquit(m, mci, e); | |
f2e44ded EA |
563 | } |
564 | \f/* | |
c428b1b2 | 565 | ** SMTPPROBE -- check the connection state |
f2e44ded EA |
566 | */ |
567 | ||
c428b1b2 | 568 | smtpprobe(mci) |
f2e44ded EA |
569 | register MCI *mci; |
570 | { | |
571 | int r; | |
572 | MAILER *m = mci->mci_mailer; | |
573 | extern ENVELOPE BlankEnvelope; | |
574 | ENVELOPE *e = &BlankEnvelope; | |
575 | ||
8e948497 | 576 | SmtpPhase = "client probe"; |
c428b1b2 | 577 | smtpmessage("RSET", m, mci); |
3001ca78 | 578 | r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); |
5d41b806 | 579 | if (r < 0 || REPLYTYPE(r) != 2) |
f2e44ded EA |
580 | smtpquit(m, mci, e); |
581 | return r; | |
582 | } | |
583 | \f/* | |
d2eb2478 EA |
584 | ** REPLY -- read arpanet reply |
585 | ** | |
586 | ** Parameters: | |
4db45bf1 | 587 | ** m -- the mailer we are reading the reply from. |
474bc899 EA |
588 | ** mci -- the mailer connection info structure. |
589 | ** e -- the current envelope. | |
590 | ** timeout -- the timeout for reads. | |
3001ca78 EA |
591 | ** pfunc -- processing function for second and subsequent |
592 | ** lines of response -- if null, no special | |
593 | ** processing is done. | |
d2eb2478 EA |
594 | ** |
595 | ** Returns: | |
596 | ** reply code it reads. | |
597 | ** | |
598 | ** Side Effects: | |
599 | ** flushes the mail file. | |
600 | */ | |
601 | ||
3001ca78 | 602 | reply(m, mci, e, timeout, pfunc) |
1dbda134 | 603 | MAILER *m; |
f2e44ded | 604 | MCI *mci; |
e62e1144 | 605 | ENVELOPE *e; |
3001ca78 EA |
606 | time_t timeout; |
607 | void (*pfunc)(); | |
d2eb2478 | 608 | { |
cb452ecf EA |
609 | register char *bufp; |
610 | register int r; | |
3001ca78 | 611 | bool firstline = TRUE; |
a9bac7a9 EA |
612 | char junkbuf[MAXLINE]; |
613 | ||
474bc899 EA |
614 | if (mci->mci_out != NULL) |
615 | (void) fflush(mci->mci_out); | |
42281a7d | 616 | |
9678c96d | 617 | if (tTd(18, 1)) |
42281a7d | 618 | printf("reply\n"); |
d2eb2478 | 619 | |
37eaaadb EA |
620 | /* |
621 | ** Read the input line, being careful not to hang. | |
622 | */ | |
623 | ||
cb452ecf | 624 | for (bufp = SmtpReplyBuffer;; bufp = junkbuf) |
d2eb2478 | 625 | { |
37eaaadb | 626 | register char *p; |
e62e1144 | 627 | extern time_t curtime(); |
37eaaadb | 628 | |
37eaaadb | 629 | /* actually do the read */ |
e62e1144 EA |
630 | if (e->e_xfp != NULL) |
631 | (void) fflush(e->e_xfp); /* for debugging */ | |
d0729491 EA |
632 | |
633 | /* if we are in the process of closing just give the code */ | |
06771186 | 634 | if (mci->mci_state == MCIS_CLOSED) |
d0729491 EA |
635 | return (SMTPCLOSING); |
636 | ||
bc854e30 EA |
637 | if (mci->mci_out != NULL) |
638 | fflush(mci->mci_out); | |
639 | ||
d0729491 | 640 | /* get the line from the other side */ |
8e948497 | 641 | p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); |
e62e1144 EA |
642 | mci->mci_lastuse = curtime(); |
643 | ||
d0729491 | 644 | if (p == NULL) |
ed7382d3 | 645 | { |
044ab67a | 646 | extern char MsgBuf[]; /* err.c */ |
044ab67a | 647 | |
46f6ec52 EA |
648 | /* if the remote end closed early, fake an error */ |
649 | if (errno == 0) | |
650 | # ifdef ECONNRESET | |
651 | errno = ECONNRESET; | |
f3d8f6d6 | 652 | # else /* ECONNRESET */ |
46f6ec52 | 653 | errno = EPIPE; |
f3d8f6d6 | 654 | # endif /* ECONNRESET */ |
46f6ec52 | 655 | |
474bc899 | 656 | mci->mci_errno = errno; |
6e99f903 | 657 | mci->mci_exitstat = EX_TEMPFAIL; |
b6edea3d | 658 | message("451 %s: reply: read error from %s", |
6e99f903 | 659 | e->e_id == NULL ? "NOQUEUE" : e->e_id, |
b8e5fc1b | 660 | mci->mci_host); |
9759fb92 EA |
661 | /* if debugging, pause so we can see state */ |
662 | if (tTd(18, 100)) | |
663 | pause(); | |
044ab67a | 664 | # ifdef LOG |
68f7099c | 665 | if (LogLevel > 1) |
b8e5fc1b | 666 | syslog(LOG_INFO, "%s", &MsgBuf[4]); |
f3d8f6d6 | 667 | # endif /* LOG */ |
f2e44ded | 668 | mci->mci_state = MCIS_ERROR; |
e62e1144 | 669 | smtpquit(m, mci, e); |
d0729491 | 670 | return (-1); |
ed7382d3 | 671 | } |
a9bac7a9 | 672 | fixcrlf(bufp, TRUE); |
37eaaadb | 673 | |
cb452ecf | 674 | if (e->e_xfp != NULL && strchr("45", bufp[0]) != NULL) |
d7dbe85b EA |
675 | { |
676 | /* serious error -- log the previous command */ | |
cb452ecf EA |
677 | if (SmtpMsgBuffer[0] != '\0') |
678 | fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); | |
679 | SmtpMsgBuffer[0] = '\0'; | |
d7dbe85b EA |
680 | |
681 | /* now log the message as from the other side */ | |
a9bac7a9 | 682 | fprintf(e->e_xfp, "<<< %s\n", bufp); |
d7dbe85b EA |
683 | } |
684 | ||
685 | /* display the input for verbose mode */ | |
dc2cd20f | 686 | if (Verbose) |
09bdfe00 | 687 | nmessage("050 %s", bufp); |
37eaaadb | 688 | |
3001ca78 EA |
689 | /* process the line */ |
690 | if (pfunc != NULL && !firstline) | |
691 | (*pfunc)(bufp, m, mci, e); | |
692 | ||
693 | firstline = FALSE; | |
694 | ||
37eaaadb | 695 | /* if continuation is required, we can go on */ |
cb452ecf EA |
696 | if (bufp[3] == '-') |
697 | continue; | |
698 | ||
699 | /* ignore improperly formated input */ | |
700 | if (!(isascii(bufp[0]) && isdigit(bufp[0]))) | |
d2eb2478 | 701 | continue; |
37eaaadb EA |
702 | |
703 | /* decode the reply code */ | |
cb452ecf | 704 | r = atoi(bufp); |
37eaaadb EA |
705 | |
706 | /* extra semantics: 0xx codes are "informational" */ | |
cb452ecf EA |
707 | if (r >= 100) |
708 | break; | |
709 | } | |
37eaaadb | 710 | |
cb452ecf EA |
711 | /* |
712 | ** Now look at SmtpReplyBuffer -- only care about the first | |
713 | ** line of the response from here on out. | |
714 | */ | |
5d41b806 | 715 | |
cb452ecf EA |
716 | /* save temporary failure messages for posterity */ |
717 | if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') | |
718 | (void) strcpy(SmtpError, SmtpReplyBuffer); | |
80482eb5 | 719 | |
cb452ecf EA |
720 | /* reply code 421 is "Service Shutting Down" */ |
721 | if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) | |
722 | { | |
723 | /* send the quit protocol */ | |
724 | mci->mci_state = MCIS_SSD; | |
725 | smtpquit(m, mci, e); | |
d2eb2478 | 726 | } |
cb452ecf EA |
727 | |
728 | return (r); | |
d2eb2478 | 729 | } |
42281a7d | 730 | \f/* |
e6b0a75b | 731 | ** SMTPMESSAGE -- send message to server |
42281a7d EA |
732 | ** |
733 | ** Parameters: | |
734 | ** f -- format | |
4db45bf1 | 735 | ** m -- the mailer to control formatting. |
42281a7d EA |
736 | ** a, b, c -- parameters |
737 | ** | |
738 | ** Returns: | |
739 | ** none. | |
740 | ** | |
741 | ** Side Effects: | |
06771186 | 742 | ** writes message to mci->mci_out. |
42281a7d EA |
743 | */ |
744 | ||
e6b0a75b | 745 | /*VARARGS1*/ |
6e99f903 EA |
746 | #ifdef __STDC__ |
747 | smtpmessage(char *f, MAILER *m, MCI *mci, ...) | |
748 | #else | |
749 | smtpmessage(f, m, mci, va_alist) | |
42281a7d | 750 | char *f; |
4db45bf1 | 751 | MAILER *m; |
f2e44ded | 752 | MCI *mci; |
6e99f903 EA |
753 | va_dcl |
754 | #endif | |
42281a7d | 755 | { |
5229f34d EA |
756 | VA_LOCAL_DECL |
757 | ||
07b49560 | 758 | VA_START(mci); |
5229f34d EA |
759 | (void) vsprintf(SmtpMsgBuffer, f, ap); |
760 | VA_END; | |
bc854e30 | 761 | |
dc2cd20f | 762 | if (tTd(18, 1) || Verbose) |
b6edea3d | 763 | nmessage(">>> %s", SmtpMsgBuffer); |
06771186 | 764 | if (mci->mci_out != NULL) |
bc854e30 | 765 | { |
06771186 | 766 | fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, |
f2e44ded | 767 | m == NULL ? "\r\n" : m->m_eol); |
bc854e30 | 768 | } |
80ec420e | 769 | else if (tTd(18, 1)) |
0852beb8 | 770 | { |
80ec420e | 771 | printf("smtpmessage: NULL mci_out\n"); |
0852beb8 | 772 | } |
42281a7d | 773 | } |
884a20cb | 774 | |
f3d8f6d6 | 775 | # endif /* SMTP */ |