Commit | Line | Data |
---|---|---|
b2a81223 | 1 | /* |
dc45ba8c | 2 | * Copyright (c) 1983 Eric P. Allman |
bee79b64 KB |
3 | * Copyright (c) 1988 Regents of the University of California. |
4 | * All rights reserved. | |
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 | |
a9bac7a9 | 13 | static char sccsid[] = "@(#)usersmtp.c 6.22 (Berkeley) %G% (with SMTP)"; |
bee79b64 | 14 | #else |
a9bac7a9 | 15 | static char sccsid[] = "@(#)usersmtp.c 6.22 (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; |
140717b5 | 66 | extern STAB *stab(); |
d2eb2478 | 67 | |
474bc899 EA |
68 | if (tTd(17, 1)) |
69 | { | |
70 | printf("smtpinit "); | |
71 | mci_dump(mci); | |
72 | } | |
73 | ||
e6b0a75b EA |
74 | /* |
75 | ** Open the connection to the mailer. | |
76 | */ | |
d2eb2478 | 77 | |
46f6ec52 | 78 | SmtpError[0] = '\0'; |
474bc899 | 79 | CurHostName = mci->mci_host; /* XXX UGLY XXX */ |
f2e44ded | 80 | switch (mci->mci_state) |
1ea752a1 | 81 | { |
f2e44ded EA |
82 | case MCIS_ACTIVE: |
83 | /* need to clear old information */ | |
84 | smtprset(m, mci, e); | |
263c5860 | 85 | /* fall through */ |
46f6ec52 | 86 | |
f2e44ded EA |
87 | case MCIS_OPEN: |
88 | return; | |
89 | ||
90 | case MCIS_ERROR: | |
91 | case MCIS_SSD: | |
92 | /* shouldn't happen */ | |
93 | smtpquit(m, mci, e); | |
263c5860 | 94 | /* fall through */ |
f2e44ded EA |
95 | |
96 | case MCIS_CLOSED: | |
b6edea3d | 97 | syserr("451 smtpinit: state CLOSED"); |
f2e44ded EA |
98 | return; |
99 | ||
100 | case MCIS_OPENING: | |
101 | break; | |
1ea752a1 | 102 | } |
d2eb2478 | 103 | |
474bc899 | 104 | SmtpPhase = mci->mci_phase = "user open"; |
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 | |
474bc899 | 113 | SmtpPhase = mci->mci_phase = "greeting wait"; |
e62e1144 | 114 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
7f5e2eef | 115 | r = reply(m, mci, e, TimeOuts.to_initial); |
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 | ||
e62e1144 | 124 | smtpmessage("HELO %s", m, mci, MyHostName); |
474bc899 | 125 | SmtpPhase = mci->mci_phase = "HELO wait"; |
e62e1144 | 126 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
7f5e2eef | 127 | r = reply(m, mci, e, TimeOuts.to_helo); |
3ff6d543 | 128 | if (r < 0) |
07cb6633 | 129 | goto tempfail1; |
3ff6d543 | 130 | else if (REPLYTYPE(r) == 5) |
057a9c5d | 131 | goto unavailable; |
4672197a | 132 | else if (REPLYTYPE(r) != 2) |
07cb6633 | 133 | goto tempfail1; |
4a4ebe09 | 134 | |
a9bac7a9 EA |
135 | /* |
136 | ** Check to see if we actually ended up talking to ourself. | |
137 | ** This means we didn't know about an alias or MX, or we managed | |
138 | ** to connect to an echo server. | |
139 | */ | |
140 | ||
141 | p = strchr(SmtpReplyBuffer, ' '); | |
142 | if (p != NULL) | |
143 | *p == '\0'; | |
144 | if (strcasecmp(SmtpReplyBuffer, MyHostName) == 0) | |
145 | { | |
146 | syserr("553 %s config error: mail loops back to myself", | |
147 | MyHostName); | |
148 | mci->mci_exitstat = EX_CONFIG; | |
149 | mci->mci_errno = 0; | |
150 | smtpquit(m, mci, e); | |
151 | return; | |
152 | } | |
153 | ||
8fe4fb9b EA |
154 | /* |
155 | ** If this is expected to be another sendmail, send some internal | |
156 | ** commands. | |
157 | */ | |
158 | ||
1dbda134 | 159 | if (bitnset(M_INTERNAL, m->m_flags)) |
8fe4fb9b EA |
160 | { |
161 | /* tell it to be verbose */ | |
e62e1144 | 162 | smtpmessage("VERB", m, mci); |
7f5e2eef | 163 | r = reply(m, mci, e, TimeOuts.to_miscshort); |
8fe4fb9b | 164 | if (r < 0) |
07cb6633 | 165 | goto tempfail2; |
8fe4fb9b EA |
166 | } |
167 | ||
e62e1144 | 168 | mci->mci_state = MCIS_OPEN; |
f2e44ded | 169 | return; |
e62e1144 EA |
170 | |
171 | tempfail1: | |
172 | tempfail2: | |
173 | mci->mci_exitstat = EX_TEMPFAIL; | |
474bc899 EA |
174 | if (mci->mci_errno == 0) |
175 | mci->mci_errno = errno; | |
176 | if (mci->mci_state != MCIS_CLOSED) | |
177 | smtpquit(m, mci, e); | |
f2e44ded | 178 | return; |
e62e1144 EA |
179 | |
180 | unavailable: | |
181 | mci->mci_exitstat = EX_UNAVAILABLE; | |
182 | mci->mci_errno = errno; | |
183 | smtpquit(m, mci, e); | |
f2e44ded | 184 | return; |
e62e1144 EA |
185 | } |
186 | ||
187 | smtpmailfrom(m, mci, e) | |
188 | struct mailer *m; | |
f2e44ded | 189 | MCI *mci; |
e62e1144 EA |
190 | ENVELOPE *e; |
191 | { | |
192 | int r; | |
193 | char buf[MAXNAME]; | |
194 | ||
322eceee EA |
195 | if (tTd(17, 2)) |
196 | printf("smtpmailfrom: CurHost=%s\n", CurHostName); | |
197 | ||
7d7fdf93 EA |
198 | /* |
199 | ** Send the HOPS command. | |
200 | ** This is non-standard and may give an "unknown command". | |
201 | ** This is not an error. | |
202 | ** It can give a "bad hop count" error if the hop | |
203 | ** count is exceeded. | |
204 | */ | |
205 | ||
e6b0a75b EA |
206 | /* |
207 | ** Send the MAIL command. | |
208 | ** Designates the sender. | |
209 | */ | |
42281a7d | 210 | |
e62e1144 EA |
211 | mci->mci_state = MCIS_ACTIVE; |
212 | ||
bc854e30 EA |
213 | if (bitset(EF_RESPONSE, e->e_flags)) |
214 | (void) strcpy(buf, ""); | |
215 | else | |
216 | expand("\201g", buf, &buf[sizeof buf - 1], e); | |
e62e1144 | 217 | if (e->e_from.q_mailer == LocalMailer || |
1dbda134 | 218 | !bitnset(M_FROMPATH, m->m_flags)) |
6abb7b86 | 219 | { |
e62e1144 | 220 | smtpmessage("MAIL From:<%s>", m, mci, buf); |
6abb7b86 EA |
221 | } |
222 | else | |
223 | { | |
e62e1144 | 224 | smtpmessage("MAIL From:<@%s%c%s>", m, mci, MyHostName, |
532c9874 | 225 | buf[0] == '@' ? ',' : ':', buf); |
6abb7b86 | 226 | } |
474bc899 | 227 | SmtpPhase = mci->mci_phase = "MAIL wait"; |
e62e1144 | 228 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
7f5e2eef | 229 | r = reply(m, mci, e, TimeOuts.to_mail); |
3ff6d543 | 230 | if (r < 0 || REPLYTYPE(r) == 4) |
e62e1144 EA |
231 | { |
232 | mci->mci_exitstat = EX_TEMPFAIL; | |
233 | mci->mci_errno = errno; | |
234 | smtpquit(m, mci, e); | |
e62e1144 EA |
235 | return EX_TEMPFAIL; |
236 | } | |
4672197a | 237 | else if (r == 250) |
e62e1144 EA |
238 | { |
239 | mci->mci_exitstat = EX_OK; | |
240 | return EX_OK; | |
241 | } | |
4672197a | 242 | else if (r == 552) |
e62e1144 EA |
243 | { |
244 | /* signal service unavailable */ | |
245 | mci->mci_exitstat = EX_UNAVAILABLE; | |
246 | smtpquit(m, mci, e); | |
e62e1144 EA |
247 | return EX_UNAVAILABLE; |
248 | } | |
057a9c5d | 249 | |
51d9cc47 | 250 | #ifdef LOG |
68f7099c | 251 | if (LogLevel > 1) |
51d9cc47 EA |
252 | { |
253 | syslog(LOG_CRIT, "%s: SMTP MAIL protocol error: %s", | |
254 | e->e_id, SmtpReplyBuffer); | |
255 | } | |
256 | #endif | |
257 | ||
057a9c5d | 258 | /* protocol error -- close up */ |
e62e1144 EA |
259 | smtpquit(m, mci, e); |
260 | mci->mci_exitstat = EX_PROTOCOL; | |
e62e1144 | 261 | return EX_PROTOCOL; |
d2eb2478 EA |
262 | } |
263 | \f/* | |
4a4ebe09 | 264 | ** SMTPRCPT -- designate recipient. |
3c6123ce EA |
265 | ** |
266 | ** Parameters: | |
e6b0a75b | 267 | ** to -- address of recipient. |
4db45bf1 | 268 | ** m -- the mailer we are sending to. |
474bc899 EA |
269 | ** mci -- the connection info for this transaction. |
270 | ** e -- the envelope for this transaction. | |
3c6123ce EA |
271 | ** |
272 | ** Returns: | |
e6b0a75b | 273 | ** exit status corresponding to recipient status. |
3c6123ce EA |
274 | ** |
275 | ** Side Effects: | |
e6b0a75b | 276 | ** Sends the mail via SMTP. |
3c6123ce EA |
277 | */ |
278 | ||
e62e1144 | 279 | smtprcpt(to, m, mci, e) |
e6b0a75b | 280 | ADDRESS *to; |
4db45bf1 | 281 | register MAILER *m; |
f2e44ded | 282 | MCI *mci; |
e62e1144 | 283 | ENVELOPE *e; |
3c6123ce EA |
284 | { |
285 | register int r; | |
286 | ||
e62e1144 | 287 | smtpmessage("RCPT To:<%s>", m, mci, to->q_user); |
e6b0a75b | 288 | |
474bc899 | 289 | SmtpPhase = mci->mci_phase = "RCPT wait"; |
e62e1144 | 290 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
7f5e2eef | 291 | r = reply(m, mci, e, TimeOuts.to_rcpt); |
3ff6d543 | 292 | if (r < 0 || REPLYTYPE(r) == 4) |
e6b0a75b | 293 | return (EX_TEMPFAIL); |
4672197a EA |
294 | else if (REPLYTYPE(r) == 2) |
295 | return (EX_OK); | |
977ccbaf EA |
296 | else if (r == 550 || r == 551 || r == 553) |
297 | return (EX_NOUSER); | |
298 | else if (r == 552 || r == 554) | |
299 | return (EX_UNAVAILABLE); | |
51d9cc47 EA |
300 | |
301 | #ifdef LOG | |
68f7099c | 302 | if (LogLevel > 1) |
51d9cc47 EA |
303 | { |
304 | syslog(LOG_CRIT, "%s: SMTP RCPT protocol error: %s", | |
305 | e->e_id, SmtpReplyBuffer); | |
306 | } | |
307 | #endif | |
308 | ||
977ccbaf | 309 | return (EX_PROTOCOL); |
3c6123ce EA |
310 | } |
311 | \f/* | |
4db45bf1 | 312 | ** SMTPDATA -- send the data and clean up the transaction. |
d2eb2478 EA |
313 | ** |
314 | ** Parameters: | |
e6b0a75b | 315 | ** m -- mailer being sent to. |
dd1fe05b | 316 | ** e -- the envelope for this message. |
d2eb2478 EA |
317 | ** |
318 | ** Returns: | |
4a4ebe09 | 319 | ** exit status corresponding to DATA command. |
d2eb2478 EA |
320 | ** |
321 | ** Side Effects: | |
e6b0a75b | 322 | ** none. |
d2eb2478 EA |
323 | */ |
324 | ||
06771186 | 325 | smtpdata(m, mci, e) |
e6b0a75b | 326 | struct mailer *m; |
f2e44ded | 327 | register MCI *mci; |
dd1fe05b | 328 | register ENVELOPE *e; |
d2eb2478 EA |
329 | { |
330 | register int r; | |
d2eb2478 | 331 | |
3c6123ce EA |
332 | /* |
333 | ** Send the data. | |
4db45bf1 EA |
334 | ** First send the command and check that it is ok. |
335 | ** Then send the data. | |
336 | ** Follow it up with a dot to terminate. | |
337 | ** Finally get the results of the transaction. | |
3c6123ce EA |
338 | */ |
339 | ||
4db45bf1 | 340 | /* send the command and check ok to proceed */ |
e62e1144 | 341 | smtpmessage("DATA", m, mci); |
474bc899 | 342 | SmtpPhase = mci->mci_phase = "DATA wait"; |
e62e1144 | 343 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
7f5e2eef | 344 | r = reply(m, mci, e, TimeOuts.to_datainit); |
3ff6d543 | 345 | if (r < 0 || REPLYTYPE(r) == 4) |
c6f2ede6 EA |
346 | { |
347 | smtpquit(m, mci, e); | |
3c6123ce | 348 | return (EX_TEMPFAIL); |
c6f2ede6 | 349 | } |
4672197a | 350 | else if (r == 554) |
c6f2ede6 EA |
351 | { |
352 | smtprset(m, mci, e); | |
4672197a | 353 | return (EX_UNAVAILABLE); |
c6f2ede6 | 354 | } |
4672197a | 355 | else if (r != 354) |
c6f2ede6 | 356 | { |
51d9cc47 | 357 | #ifdef LOG |
68f7099c | 358 | if (LogLevel > 1) |
51d9cc47 EA |
359 | { |
360 | syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s", | |
361 | e->e_id, SmtpReplyBuffer); | |
362 | } | |
363 | #endif | |
c6f2ede6 | 364 | smtprset(m, mci, e); |
977ccbaf | 365 | return (EX_PROTOCOL); |
c6f2ede6 | 366 | } |
4db45bf1 EA |
367 | |
368 | /* now output the actual message */ | |
e62e1144 | 369 | (*e->e_puthdr)(mci->mci_out, m, e); |
06771186 | 370 | putline("\n", mci->mci_out, m); |
e62e1144 | 371 | (*e->e_putbody)(mci->mci_out, m, e); |
4db45bf1 EA |
372 | |
373 | /* terminate the message */ | |
06771186 | 374 | fprintf(mci->mci_out, ".%s", m->m_eol); |
dc2cd20f | 375 | if (Verbose) |
b6edea3d | 376 | nmessage(">>> ."); |
4db45bf1 EA |
377 | |
378 | /* check for the results of the transaction */ | |
474bc899 | 379 | SmtpPhase = mci->mci_phase = "result wait"; |
e62e1144 | 380 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
7f5e2eef | 381 | r = reply(m, mci, e, TimeOuts.to_datafinal); |
e62e1144 | 382 | if (r < 0) |
c6f2ede6 EA |
383 | { |
384 | smtpquit(m, mci, e); | |
e62e1144 | 385 | return (EX_TEMPFAIL); |
c6f2ede6 | 386 | } |
e62e1144 | 387 | mci->mci_state = MCIS_OPEN; |
614b4258 | 388 | e->e_statmsg = newstr(&SmtpReplyBuffer[4]); |
e62e1144 | 389 | if (REPLYTYPE(r) == 4) |
3c6123ce | 390 | return (EX_TEMPFAIL); |
4672197a EA |
391 | else if (r == 250) |
392 | return (EX_OK); | |
393 | else if (r == 552 || r == 554) | |
394 | return (EX_UNAVAILABLE); | |
51d9cc47 | 395 | #ifdef LOG |
68f7099c | 396 | if (LogLevel > 1) |
51d9cc47 EA |
397 | { |
398 | syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s", | |
399 | e->e_id, SmtpReplyBuffer); | |
400 | } | |
401 | #endif | |
977ccbaf | 402 | return (EX_PROTOCOL); |
d2eb2478 EA |
403 | } |
404 | \f/* | |
e6b0a75b EA |
405 | ** SMTPQUIT -- close the SMTP connection. |
406 | ** | |
407 | ** Parameters: | |
e009f4f4 | 408 | ** m -- a pointer to the mailer. |
e6b0a75b EA |
409 | ** |
410 | ** Returns: | |
411 | ** none. | |
412 | ** | |
413 | ** Side Effects: | |
414 | ** sends the final protocol and closes the connection. | |
415 | */ | |
416 | ||
e62e1144 | 417 | smtpquit(m, mci, e) |
06771186 | 418 | register MAILER *m; |
f2e44ded | 419 | register MCI *mci; |
e62e1144 | 420 | ENVELOPE *e; |
e6b0a75b | 421 | { |
80482eb5 | 422 | int i; |
e6b0a75b | 423 | |
f2e44ded | 424 | /* send the quit message if we haven't gotten I/O error */ |
e62e1144 | 425 | if (mci->mci_state != MCIS_ERROR) |
044ab67a | 426 | { |
e62e1144 | 427 | smtpmessage("QUIT", m, mci); |
7f5e2eef | 428 | (void) reply(m, mci, e, TimeOuts.to_quit); |
06771186 | 429 | if (mci->mci_state == MCIS_CLOSED) |
11957f11 | 430 | return; |
80482eb5 EA |
431 | } |
432 | ||
2ae0e0ed | 433 | /* now actually close the connection and pick up the zombie */ |
ffc1c1a0 | 434 | i = endmailer(mci, e, m->m_argv); |
80482eb5 | 435 | if (i != EX_OK) |
b6edea3d | 436 | syserr("451 smtpquit %s: stat %d", m->m_argv[0], i); |
e6b0a75b EA |
437 | } |
438 | \f/* | |
f2e44ded EA |
439 | ** SMTPRSET -- send a RSET (reset) command |
440 | */ | |
441 | ||
442 | smtprset(m, mci, e) | |
443 | register MAILER *m; | |
444 | register MCI *mci; | |
445 | ENVELOPE *e; | |
446 | { | |
447 | int r; | |
448 | ||
449 | smtpmessage("RSET", m, mci); | |
7f5e2eef | 450 | r = reply(m, mci, e, TimeOuts.to_rset); |
263c5860 EA |
451 | if (r < 0) |
452 | mci->mci_state = MCIS_ERROR; | |
f2e44ded | 453 | else if (REPLYTYPE(r) == 2) |
263c5860 EA |
454 | { |
455 | mci->mci_state = MCIS_OPEN; | |
456 | return; | |
457 | } | |
458 | smtpquit(m, mci, e); | |
f2e44ded EA |
459 | } |
460 | \f/* | |
c428b1b2 | 461 | ** SMTPPROBE -- check the connection state |
f2e44ded EA |
462 | */ |
463 | ||
c428b1b2 | 464 | smtpprobe(mci) |
f2e44ded EA |
465 | register MCI *mci; |
466 | { | |
467 | int r; | |
468 | MAILER *m = mci->mci_mailer; | |
469 | extern ENVELOPE BlankEnvelope; | |
470 | ENVELOPE *e = &BlankEnvelope; | |
471 | ||
c428b1b2 | 472 | smtpmessage("RSET", m, mci); |
7f5e2eef | 473 | r = reply(m, mci, e, TimeOuts.to_miscshort); |
5d41b806 | 474 | if (r < 0 || REPLYTYPE(r) != 2) |
f2e44ded EA |
475 | smtpquit(m, mci, e); |
476 | return r; | |
477 | } | |
478 | \f/* | |
d2eb2478 EA |
479 | ** REPLY -- read arpanet reply |
480 | ** | |
481 | ** Parameters: | |
4db45bf1 | 482 | ** m -- the mailer we are reading the reply from. |
474bc899 EA |
483 | ** mci -- the mailer connection info structure. |
484 | ** e -- the current envelope. | |
485 | ** timeout -- the timeout for reads. | |
d2eb2478 EA |
486 | ** |
487 | ** Returns: | |
488 | ** reply code it reads. | |
489 | ** | |
490 | ** Side Effects: | |
491 | ** flushes the mail file. | |
492 | */ | |
493 | ||
474bc899 | 494 | reply(m, mci, e, timeout) |
1dbda134 | 495 | MAILER *m; |
f2e44ded | 496 | MCI *mci; |
e62e1144 | 497 | ENVELOPE *e; |
d2eb2478 | 498 | { |
a9bac7a9 EA |
499 | char *bufp = SmtpReplyBuffer; |
500 | char junkbuf[MAXLINE]; | |
501 | ||
474bc899 EA |
502 | if (mci->mci_out != NULL) |
503 | (void) fflush(mci->mci_out); | |
42281a7d | 504 | |
9678c96d | 505 | if (tTd(18, 1)) |
42281a7d | 506 | printf("reply\n"); |
d2eb2478 | 507 | |
37eaaadb EA |
508 | /* |
509 | ** Read the input line, being careful not to hang. | |
510 | */ | |
511 | ||
a9bac7a9 | 512 | for (;; bufp = junkbuf) |
d2eb2478 | 513 | { |
d2eb2478 | 514 | register int r; |
37eaaadb | 515 | register char *p; |
e62e1144 | 516 | extern time_t curtime(); |
37eaaadb | 517 | |
37eaaadb | 518 | /* actually do the read */ |
e62e1144 EA |
519 | if (e->e_xfp != NULL) |
520 | (void) fflush(e->e_xfp); /* for debugging */ | |
d0729491 EA |
521 | |
522 | /* if we are in the process of closing just give the code */ | |
06771186 | 523 | if (mci->mci_state == MCIS_CLOSED) |
d0729491 EA |
524 | return (SMTPCLOSING); |
525 | ||
bc854e30 EA |
526 | if (mci->mci_out != NULL) |
527 | fflush(mci->mci_out); | |
528 | ||
d0729491 | 529 | /* get the line from the other side */ |
a9bac7a9 | 530 | p = sfgets(bufp, MAXLINE, mci->mci_in, timeout); |
e62e1144 EA |
531 | mci->mci_lastuse = curtime(); |
532 | ||
d0729491 | 533 | if (p == NULL) |
ed7382d3 | 534 | { |
044ab67a | 535 | extern char MsgBuf[]; /* err.c */ |
044ab67a | 536 | |
46f6ec52 EA |
537 | /* if the remote end closed early, fake an error */ |
538 | if (errno == 0) | |
539 | # ifdef ECONNRESET | |
540 | errno = ECONNRESET; | |
f3d8f6d6 | 541 | # else /* ECONNRESET */ |
46f6ec52 | 542 | errno = EPIPE; |
f3d8f6d6 | 543 | # endif /* ECONNRESET */ |
46f6ec52 | 544 | |
474bc899 | 545 | mci->mci_errno = errno; |
6e99f903 | 546 | mci->mci_exitstat = EX_TEMPFAIL; |
b6edea3d | 547 | message("451 %s: reply: read error from %s", |
6e99f903 | 548 | e->e_id == NULL ? "NOQUEUE" : e->e_id, |
b8e5fc1b | 549 | mci->mci_host); |
9759fb92 EA |
550 | /* if debugging, pause so we can see state */ |
551 | if (tTd(18, 100)) | |
552 | pause(); | |
044ab67a | 553 | # ifdef LOG |
68f7099c | 554 | if (LogLevel > 1) |
b8e5fc1b | 555 | syslog(LOG_INFO, "%s", &MsgBuf[4]); |
f3d8f6d6 | 556 | # endif /* LOG */ |
f2e44ded | 557 | mci->mci_state = MCIS_ERROR; |
e62e1144 | 558 | smtpquit(m, mci, e); |
d0729491 | 559 | return (-1); |
ed7382d3 | 560 | } |
a9bac7a9 | 561 | fixcrlf(bufp, TRUE); |
37eaaadb | 562 | |
f3d8f6d6 | 563 | if (e->e_xfp != NULL && strchr("45", SmtpReplyBuffer[0]) != NULL) |
d7dbe85b EA |
564 | { |
565 | /* serious error -- log the previous command */ | |
a9bac7a9 EA |
566 | if (bufp[0] != '\0') |
567 | fprintf(e->e_xfp, ">>> %s\n", bufp); | |
568 | bufp[0] = '\0'; | |
d7dbe85b EA |
569 | |
570 | /* now log the message as from the other side */ | |
a9bac7a9 | 571 | fprintf(e->e_xfp, "<<< %s\n", bufp); |
d7dbe85b EA |
572 | } |
573 | ||
574 | /* display the input for verbose mode */ | |
dc2cd20f | 575 | if (Verbose) |
a9bac7a9 | 576 | nmessage("%s", bufp); |
37eaaadb EA |
577 | |
578 | /* if continuation is required, we can go on */ | |
a9bac7a9 EA |
579 | if (bufp[3] == '-' || |
580 | !(isascii(bufp[0]) && isdigit(bufp[0]))) | |
d2eb2478 | 581 | continue; |
37eaaadb EA |
582 | |
583 | /* decode the reply code */ | |
80482eb5 | 584 | r = atoi(SmtpReplyBuffer); |
37eaaadb EA |
585 | |
586 | /* extra semantics: 0xx codes are "informational" */ | |
d2eb2478 EA |
587 | if (r < 100) |
588 | continue; | |
37eaaadb | 589 | |
5d41b806 EA |
590 | /* save temporary failure messages for posterity */ |
591 | if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') | |
592 | (void) strcpy(SmtpError, SmtpReplyBuffer); | |
593 | ||
80482eb5 | 594 | /* reply code 421 is "Service Shutting Down" */ |
06771186 | 595 | if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) |
80482eb5 | 596 | { |
d0729491 | 597 | /* send the quit protocol */ |
06771186 | 598 | mci->mci_state = MCIS_SSD; |
e62e1144 | 599 | smtpquit(m, mci, e); |
80482eb5 EA |
600 | } |
601 | ||
d2eb2478 EA |
602 | return (r); |
603 | } | |
604 | } | |
42281a7d | 605 | \f/* |
e6b0a75b | 606 | ** SMTPMESSAGE -- send message to server |
42281a7d EA |
607 | ** |
608 | ** Parameters: | |
609 | ** f -- format | |
4db45bf1 | 610 | ** m -- the mailer to control formatting. |
42281a7d EA |
611 | ** a, b, c -- parameters |
612 | ** | |
613 | ** Returns: | |
614 | ** none. | |
615 | ** | |
616 | ** Side Effects: | |
06771186 | 617 | ** writes message to mci->mci_out. |
42281a7d EA |
618 | */ |
619 | ||
e6b0a75b | 620 | /*VARARGS1*/ |
6e99f903 EA |
621 | #ifdef __STDC__ |
622 | smtpmessage(char *f, MAILER *m, MCI *mci, ...) | |
623 | #else | |
624 | smtpmessage(f, m, mci, va_alist) | |
42281a7d | 625 | char *f; |
4db45bf1 | 626 | MAILER *m; |
f2e44ded | 627 | MCI *mci; |
6e99f903 EA |
628 | va_dcl |
629 | #endif | |
42281a7d | 630 | { |
5229f34d EA |
631 | VA_LOCAL_DECL |
632 | ||
07b49560 | 633 | VA_START(mci); |
5229f34d EA |
634 | (void) vsprintf(SmtpMsgBuffer, f, ap); |
635 | VA_END; | |
bc854e30 | 636 | |
dc2cd20f | 637 | if (tTd(18, 1) || Verbose) |
b6edea3d | 638 | nmessage(">>> %s", SmtpMsgBuffer); |
06771186 | 639 | if (mci->mci_out != NULL) |
bc854e30 | 640 | { |
06771186 | 641 | fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, |
f2e44ded | 642 | m == NULL ? "\r\n" : m->m_eol); |
bc854e30 EA |
643 | } |
644 | else | |
0852beb8 | 645 | { |
bc854e30 | 646 | syserr("smtpmessage: NULL mci_out"); |
0852beb8 | 647 | } |
42281a7d | 648 | } |
884a20cb | 649 | |
f3d8f6d6 | 650 | # endif /* SMTP */ |