Commit | Line | Data |
---|---|---|
b2a81223 | 1 | /* |
792e6158 | 2 | * Copyright (c) 1983, 1995 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 | |
a5386d1b | 13 | static char sccsid[] = "@(#)usersmtp.c 8.56 (Berkeley) %G% (with SMTP)"; |
bee79b64 | 14 | #else |
a5386d1b | 15 | static char sccsid[] = "@(#)usersmtp.c 8.56 (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 */ |
337a0030 | 38 | bool SmtpNeedIntro; /* need "while talking" in transcript */ |
16133a1c | 39 | |
179d940c | 40 | extern void smtpmessage __P((char *f, MAILER *m, MCI *mci, ...)); |
80482eb5 | 41 | \f/* |
e6b0a75b | 42 | ** SMTPINIT -- initialize SMTP. |
d2eb2478 | 43 | ** |
e6b0a75b | 44 | ** Opens the connection and sends the initial protocol. |
d2eb2478 EA |
45 | ** |
46 | ** Parameters: | |
e6b0a75b EA |
47 | ** m -- mailer to create connection to. |
48 | ** pvp -- pointer to parameter vector to pass to | |
49 | ** the mailer. | |
d2eb2478 EA |
50 | ** |
51 | ** Returns: | |
f2e44ded | 52 | ** none. |
d2eb2478 EA |
53 | ** |
54 | ** Side Effects: | |
e6b0a75b | 55 | ** creates connection and sends initial protocol. |
d2eb2478 EA |
56 | */ |
57 | ||
179d940c | 58 | void |
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 | |
8e5c6745 | 69 | if (tTd(18, 1)) |
474bc899 EA |
70 | { |
71 | printf("smtpinit "); | |
deff97fd | 72 | mci_dump(mci, FALSE); |
474bc899 EA |
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 */ |
39f3bc06 EA |
81 | if (CurHostName == NULL) |
82 | CurHostName = MyHostName; | |
337a0030 | 83 | SmtpNeedIntro = TRUE; |
f2e44ded | 84 | switch (mci->mci_state) |
1ea752a1 | 85 | { |
f2e44ded EA |
86 | case MCIS_ACTIVE: |
87 | /* need to clear old information */ | |
88 | smtprset(m, mci, e); | |
263c5860 | 89 | /* fall through */ |
46f6ec52 | 90 | |
f2e44ded EA |
91 | case MCIS_OPEN: |
92 | return; | |
93 | ||
94 | case MCIS_ERROR: | |
95 | case MCIS_SSD: | |
96 | /* shouldn't happen */ | |
97 | smtpquit(m, mci, e); | |
263c5860 | 98 | /* fall through */ |
f2e44ded EA |
99 | |
100 | case MCIS_CLOSED: | |
b6edea3d | 101 | syserr("451 smtpinit: state CLOSED"); |
f2e44ded EA |
102 | return; |
103 | ||
104 | case MCIS_OPENING: | |
105 | break; | |
1ea752a1 | 106 | } |
d2eb2478 | 107 | |
f2e44ded EA |
108 | mci->mci_state = MCIS_OPENING; |
109 | ||
e6b0a75b EA |
110 | /* |
111 | ** Get the greeting message. | |
057a9c5d | 112 | ** This should appear spontaneously. Give it five minutes to |
e4581b86 | 113 | ** happen. |
e6b0a75b | 114 | */ |
3c6123ce | 115 | |
8e948497 | 116 | SmtpPhase = mci->mci_phase = "client greeting"; |
e62e1144 | 117 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
77c24e97 | 118 | r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check); |
4990fc15 | 119 | if (r < 0 || REPLYTYPE(r) == 4) |
07cb6633 | 120 | goto tempfail1; |
4990fc15 EA |
121 | if (REPLYTYPE(r) != 2) |
122 | goto unavailable; | |
42281a7d | 123 | |
4a4ebe09 EA |
124 | /* |
125 | ** Send the HELO command. | |
4672197a | 126 | ** My mother taught me to always introduce myself. |
4a4ebe09 EA |
127 | */ |
128 | ||
3001ca78 EA |
129 | if (bitnset(M_ESMTP, m->m_flags)) |
130 | mci->mci_flags |= MCIF_ESMTP; | |
131 | ||
132 | tryhelo: | |
133 | if (bitset(MCIF_ESMTP, mci->mci_flags)) | |
134 | { | |
135 | smtpmessage("EHLO %s", m, mci, MyHostName); | |
8e948497 | 136 | SmtpPhase = mci->mci_phase = "client EHLO"; |
3001ca78 EA |
137 | } |
138 | else | |
139 | { | |
140 | smtpmessage("HELO %s", m, mci, MyHostName); | |
8e948497 | 141 | SmtpPhase = mci->mci_phase = "client HELO"; |
3001ca78 | 142 | } |
e62e1144 | 143 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
3001ca78 | 144 | r = reply(m, mci, e, TimeOuts.to_helo, helo_options); |
3ff6d543 | 145 | if (r < 0) |
07cb6633 | 146 | goto tempfail1; |
3ff6d543 | 147 | else if (REPLYTYPE(r) == 5) |
3001ca78 EA |
148 | { |
149 | if (bitset(MCIF_ESMTP, mci->mci_flags)) | |
150 | { | |
151 | /* try old SMTP instead */ | |
152 | mci->mci_flags &= ~MCIF_ESMTP; | |
153 | goto tryhelo; | |
154 | } | |
057a9c5d | 155 | goto unavailable; |
3001ca78 | 156 | } |
4672197a | 157 | else if (REPLYTYPE(r) != 2) |
07cb6633 | 158 | goto tempfail1; |
4a4ebe09 | 159 | |
a9bac7a9 EA |
160 | /* |
161 | ** Check to see if we actually ended up talking to ourself. | |
162 | ** This means we didn't know about an alias or MX, or we managed | |
163 | ** to connect to an echo server. | |
164 | */ | |
165 | ||
f4900dab | 166 | p = strchr(&SmtpReplyBuffer[4], ' '); |
a9bac7a9 | 167 | if (p != NULL) |
a3934270 | 168 | *p = '\0'; |
2bade550 EA |
169 | if (!bitnset(M_NOLOOPCHECK, m->m_flags) && |
170 | strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0) | |
a9bac7a9 EA |
171 | { |
172 | syserr("553 %s config error: mail loops back to myself", | |
173 | MyHostName); | |
174 | mci->mci_exitstat = EX_CONFIG; | |
175 | mci->mci_errno = 0; | |
176 | smtpquit(m, mci, e); | |
177 | return; | |
178 | } | |
179 | ||
8fe4fb9b EA |
180 | /* |
181 | ** If this is expected to be another sendmail, send some internal | |
182 | ** commands. | |
183 | */ | |
184 | ||
1dbda134 | 185 | if (bitnset(M_INTERNAL, m->m_flags)) |
8fe4fb9b EA |
186 | { |
187 | /* tell it to be verbose */ | |
e62e1144 | 188 | smtpmessage("VERB", m, mci); |
3001ca78 | 189 | r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); |
8fe4fb9b | 190 | if (r < 0) |
07cb6633 | 191 | goto tempfail2; |
8fe4fb9b EA |
192 | } |
193 | ||
b45fe690 EA |
194 | if (mci->mci_state != MCIS_CLOSED) |
195 | { | |
196 | mci->mci_state = MCIS_OPEN; | |
197 | return; | |
198 | } | |
199 | ||
200 | /* got a 421 error code during startup */ | |
e62e1144 EA |
201 | |
202 | tempfail1: | |
203 | tempfail2: | |
204 | mci->mci_exitstat = EX_TEMPFAIL; | |
474bc899 EA |
205 | if (mci->mci_errno == 0) |
206 | mci->mci_errno = errno; | |
207 | if (mci->mci_state != MCIS_CLOSED) | |
208 | smtpquit(m, mci, e); | |
f2e44ded | 209 | return; |
e62e1144 EA |
210 | |
211 | unavailable: | |
212 | mci->mci_exitstat = EX_UNAVAILABLE; | |
213 | mci->mci_errno = errno; | |
214 | smtpquit(m, mci, e); | |
f2e44ded | 215 | return; |
e62e1144 | 216 | } |
3001ca78 | 217 | \f/* |
77c24e97 EA |
218 | ** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol |
219 | ** | |
77c24e97 EA |
220 | ** Parameters: |
221 | ** line -- the response line. | |
0717d167 | 222 | ** firstline -- set if this is the first line of the reply. |
77c24e97 EA |
223 | ** m -- the mailer. |
224 | ** mci -- the mailer connection info. | |
225 | ** e -- the envelope. | |
226 | ** | |
227 | ** Returns: | |
228 | ** none. | |
229 | */ | |
230 | ||
231 | void | |
0717d167 | 232 | esmtp_check(line, firstline, m, mci, e) |
77c24e97 | 233 | char *line; |
0717d167 | 234 | bool firstline; |
77c24e97 EA |
235 | MAILER *m; |
236 | register MCI *mci; | |
237 | ENVELOPE *e; | |
238 | { | |
fd2a7ff5 EA |
239 | if (strstr(line, "ESMTP ") != NULL) |
240 | mci->mci_flags |= MCIF_ESMTP; | |
241 | if (strstr(line, "8BIT OK") != NULL) | |
242 | mci->mci_flags |= MCIF_8BITOK; | |
77c24e97 EA |
243 | } |
244 | \f/* | |
3001ca78 EA |
245 | ** HELO_OPTIONS -- process the options on a HELO line. |
246 | ** | |
247 | ** Parameters: | |
248 | ** line -- the response line. | |
0717d167 | 249 | ** firstline -- set if this is the first line of the reply. |
3001ca78 EA |
250 | ** m -- the mailer. |
251 | ** mci -- the mailer connection info. | |
252 | ** e -- the envelope. | |
253 | ** | |
254 | ** Returns: | |
255 | ** none. | |
256 | */ | |
257 | ||
258 | void | |
0717d167 | 259 | helo_options(line, firstline, m, mci, e) |
3001ca78 | 260 | char *line; |
0717d167 | 261 | bool firstline; |
3001ca78 EA |
262 | MAILER *m; |
263 | register MCI *mci; | |
264 | ENVELOPE *e; | |
265 | { | |
266 | register char *p; | |
267 | ||
fcbc62f9 | 268 | if (firstline) |
0717d167 EA |
269 | return; |
270 | ||
2604d017 | 271 | if (strlen(line) < (SIZE_T) 5) |
3001ca78 EA |
272 | return; |
273 | line += 4; | |
274 | p = strchr(line, ' '); | |
275 | if (p != NULL) | |
276 | *p++ = '\0'; | |
277 | if (strcasecmp(line, "size") == 0) | |
278 | { | |
279 | mci->mci_flags |= MCIF_SIZE; | |
280 | if (p != NULL) | |
281 | mci->mci_maxsize = atol(p); | |
282 | } | |
283 | else if (strcasecmp(line, "8bitmime") == 0) | |
23fafb99 | 284 | { |
3001ca78 | 285 | mci->mci_flags |= MCIF_8BITMIME; |
23fafb99 EA |
286 | mci->mci_flags &= ~MCIF_7BIT; |
287 | } | |
3001ca78 EA |
288 | else if (strcasecmp(line, "expn") == 0) |
289 | mci->mci_flags |= MCIF_EXPN; | |
eb381926 | 290 | else if (strcasecmp(line, "x-dsn-03") == 0) |
68d9129a | 291 | mci->mci_flags |= MCIF_DSN; |
3001ca78 EA |
292 | } |
293 | \f/* | |
294 | ** SMTPMAILFROM -- send MAIL command | |
295 | ** | |
296 | ** Parameters: | |
297 | ** m -- the mailer. | |
298 | ** mci -- the mailer connection structure. | |
299 | ** e -- the envelope (including the sender to specify). | |
300 | */ | |
e62e1144 | 301 | |
179d940c | 302 | int |
e62e1144 EA |
303 | smtpmailfrom(m, mci, e) |
304 | struct mailer *m; | |
f2e44ded | 305 | MCI *mci; |
e62e1144 EA |
306 | ENVELOPE *e; |
307 | { | |
308 | int r; | |
61fabf2e | 309 | char *bufp; |
7d858063 | 310 | char *bodytype; |
8446c922 | 311 | char buf[MAXNAME + 1]; |
3001ca78 | 312 | char optbuf[MAXLINE]; |
e62e1144 | 313 | |
8e5c6745 | 314 | if (tTd(18, 2)) |
322eceee EA |
315 | printf("smtpmailfrom: CurHost=%s\n", CurHostName); |
316 | ||
3001ca78 | 317 | /* set up appropriate options to include */ |
1a139f8c | 318 | if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0) |
3001ca78 EA |
319 | sprintf(optbuf, " SIZE=%ld", e->e_msgsize); |
320 | else | |
321 | strcpy(optbuf, ""); | |
322 | ||
7d858063 EA |
323 | bodytype = e->e_bodytype; |
324 | if (bitset(MCIF_8BITMIME, mci->mci_flags)) | |
df04c7c2 | 325 | { |
7d858063 EA |
326 | if (bodytype == NULL && |
327 | bitset(MM_MIME8BIT, MimeMode) && | |
328 | bitset(EF_HAS8BIT, e->e_flags) && | |
a5386d1b | 329 | !bitset(EF_DONT_MIME, e->e_flags) && |
7d858063 EA |
330 | !bitnset(M_8BITS, m->m_flags)) |
331 | bodytype = "8BITMIME"; | |
332 | if (bodytype != NULL) | |
df04c7c2 EA |
333 | { |
334 | strcat(optbuf, " BODY="); | |
7d858063 | 335 | strcat(optbuf, bodytype); |
df04c7c2 EA |
336 | } |
337 | } | |
bb2afea8 | 338 | else if (bitnset(M_8BITS, m->m_flags) || |
0b92c6af | 339 | !bitset(EF_HAS8BIT, e->e_flags)) |
7d858063 EA |
340 | { |
341 | /* just pass it through */ | |
342 | } | |
8bc4f1c6 | 343 | #if MIME8TO7 |
7d858063 | 344 | else if (bitset(MM_CVTMIME, MimeMode) && |
a5386d1b | 345 | !bitset(EF_DONT_MIME, e->e_flags) && |
923fa8c1 EA |
346 | (!bitset(MM_PASS8BIT, MimeMode) || |
347 | bitset(EF_IS_MIME, e->e_flags))) | |
7d858063 EA |
348 | { |
349 | /* must convert from 8bit MIME format to 7bit encoded */ | |
350 | mci->mci_flags |= MCIF_CVT8TO7; | |
351 | } | |
8bc4f1c6 | 352 | #endif |
7d858063 EA |
353 | else if (!bitset(MM_PASS8BIT, MimeMode)) |
354 | { | |
355 | /* cannot just send a 8-bit version */ | |
356 | usrerr("%s does not support 8BITMIME", mci->mci_host); | |
4e1c01f9 | 357 | mci->mci_status = "5.6.3"; |
7d858063 EA |
358 | return EX_DATAERR; |
359 | } | |
df04c7c2 | 360 | |
82e3dc75 | 361 | if (bitset(MCIF_DSN, mci->mci_flags)) |
68d9129a | 362 | { |
82e3dc75 EA |
363 | if (e->e_envid != NULL) |
364 | { | |
365 | strcat(optbuf, " ENVID="); | |
366 | strcat(optbuf, e->e_envid); | |
367 | } | |
c7a0eaaf EA |
368 | |
369 | /* RET= parameter */ | |
370 | if (bitset(EF_RET_PARAM, e->e_flags)) | |
371 | { | |
372 | strcat(optbuf, " RET="); | |
373 | if (bitset(EF_NO_BODY_RETN, e->e_flags)) | |
374 | strcat(optbuf, "HDRS"); | |
375 | else | |
376 | strcat(optbuf, "FULL"); | |
377 | } | |
68d9129a EA |
378 | } |
379 | ||
7d7fdf93 EA |
380 | /* |
381 | ** Send the HOPS command. | |
382 | ** This is non-standard and may give an "unknown command". | |
383 | ** This is not an error. | |
384 | ** It can give a "bad hop count" error if the hop | |
385 | ** count is exceeded. | |
386 | */ | |
387 | ||
e6b0a75b EA |
388 | /* |
389 | ** Send the MAIL command. | |
390 | ** Designates the sender. | |
391 | */ | |
42281a7d | 392 | |
e62e1144 EA |
393 | mci->mci_state = MCIS_ACTIVE; |
394 | ||
2cd2111f EA |
395 | if (bitset(EF_RESPONSE, e->e_flags) && |
396 | !bitnset(M_NO_NULL_FROM, m->m_flags)) | |
bc854e30 EA |
397 | (void) strcpy(buf, ""); |
398 | else | |
832e8a27 | 399 | expand("\201g", buf, sizeof buf, e); |
61fabf2e EA |
400 | if (buf[0] == '<') |
401 | { | |
402 | /* strip off <angle brackets> (put back on below) */ | |
403 | bufp = &buf[strlen(buf) - 1]; | |
404 | if (*bufp == '>') | |
405 | *bufp = '\0'; | |
406 | bufp = &buf[1]; | |
407 | } | |
408 | else | |
409 | bufp = buf; | |
2bade550 | 410 | if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) || |
1dbda134 | 411 | !bitnset(M_FROMPATH, m->m_flags)) |
6abb7b86 | 412 | { |
61fabf2e | 413 | smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf); |
6abb7b86 EA |
414 | } |
415 | else | |
416 | { | |
3001ca78 | 417 | smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, |
61fabf2e | 418 | *bufp == '@' ? ',' : ':', bufp, optbuf); |
6abb7b86 | 419 | } |
8e948497 | 420 | SmtpPhase = mci->mci_phase = "client MAIL"; |
e62e1144 | 421 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
3001ca78 | 422 | r = reply(m, mci, e, TimeOuts.to_mail, NULL); |
935403cb | 423 | if (r < 0 || r == 421) |
e62e1144 | 424 | { |
935403cb | 425 | /* communications failure/service shutting down */ |
e62e1144 EA |
426 | mci->mci_exitstat = EX_TEMPFAIL; |
427 | mci->mci_errno = errno; | |
428 | smtpquit(m, mci, e); | |
e62e1144 EA |
429 | return EX_TEMPFAIL; |
430 | } | |
935403cb EA |
431 | else if (REPLYTYPE(r) == 4) |
432 | { | |
433 | return EX_TEMPFAIL; | |
434 | } | |
4672197a | 435 | else if (r == 250) |
e62e1144 | 436 | { |
e62e1144 EA |
437 | return EX_OK; |
438 | } | |
4e1c01f9 | 439 | else if (r == 501) |
03981add | 440 | { |
4e1c01f9 EA |
441 | /* syntax error in arguments */ |
442 | mci->mci_status = "5.5.2"; | |
443 | return EX_DATAERR; | |
444 | } | |
445 | else if (r == 553) | |
446 | { | |
447 | /* mailbox name not allowed */ | |
448 | mci->mci_status = "5.1.3"; | |
03981add EA |
449 | return EX_DATAERR; |
450 | } | |
4672197a | 451 | else if (r == 552) |
e62e1144 | 452 | { |
935403cb | 453 | /* exceeded storage allocation */ |
4e1c01f9 | 454 | mci->mci_status = "5.2.2"; |
e62e1144 EA |
455 | return EX_UNAVAILABLE; |
456 | } | |
057a9c5d | 457 | |
51d9cc47 | 458 | #ifdef LOG |
68f7099c | 459 | if (LogLevel > 1) |
51d9cc47 | 460 | { |
6d3599b7 EA |
461 | syslog(LOG_CRIT, "%s: %s: SMTP MAIL protocol error: %s", |
462 | e->e_id, mci->mci_host, SmtpReplyBuffer); | |
51d9cc47 EA |
463 | } |
464 | #endif | |
465 | ||
057a9c5d | 466 | /* protocol error -- close up */ |
e62e1144 | 467 | smtpquit(m, mci, e); |
e62e1144 | 468 | return EX_PROTOCOL; |
d2eb2478 EA |
469 | } |
470 | \f/* | |
4a4ebe09 | 471 | ** SMTPRCPT -- designate recipient. |
3c6123ce EA |
472 | ** |
473 | ** Parameters: | |
e6b0a75b | 474 | ** to -- address of recipient. |
4db45bf1 | 475 | ** m -- the mailer we are sending to. |
474bc899 EA |
476 | ** mci -- the connection info for this transaction. |
477 | ** e -- the envelope for this transaction. | |
3c6123ce EA |
478 | ** |
479 | ** Returns: | |
e6b0a75b | 480 | ** exit status corresponding to recipient status. |
3c6123ce EA |
481 | ** |
482 | ** Side Effects: | |
e6b0a75b | 483 | ** Sends the mail via SMTP. |
3c6123ce EA |
484 | */ |
485 | ||
179d940c | 486 | int |
e62e1144 | 487 | smtprcpt(to, m, mci, e) |
e6b0a75b | 488 | ADDRESS *to; |
4db45bf1 | 489 | register MAILER *m; |
f2e44ded | 490 | MCI *mci; |
e62e1144 | 491 | ENVELOPE *e; |
3c6123ce EA |
492 | { |
493 | register int r; | |
68d9129a | 494 | char optbuf[MAXLINE]; |
4e1c01f9 | 495 | extern char *smtptodsn(); |
68d9129a EA |
496 | |
497 | strcpy(optbuf, ""); | |
498 | if (bitset(MCIF_DSN, mci->mci_flags)) | |
499 | { | |
3b6c2253 | 500 | /* NOTIFY= parameter */ |
66d16835 EA |
501 | if (bitset(QHASNOTIFY, to->q_flags) && |
502 | bitset(QPRIMARY, to->q_flags)) | |
82e3dc75 | 503 | { |
e1f691b3 EA |
504 | bool firstone = TRUE; |
505 | ||
506 | strcat(optbuf, " NOTIFY="); | |
507 | if (bitset(QPINGONSUCCESS, to->q_flags)) | |
508 | { | |
509 | strcat(optbuf, "SUCCESS"); | |
510 | firstone = FALSE; | |
511 | } | |
512 | if (bitset(QPINGONFAILURE, to->q_flags)) | |
513 | { | |
514 | if (!firstone) | |
515 | strcat(optbuf, ","); | |
516 | strcat(optbuf, "FAILURE"); | |
517 | firstone = FALSE; | |
518 | } | |
519 | if (bitset(QPINGONDELAY, to->q_flags)) | |
520 | { | |
521 | if (!firstone) | |
522 | strcat(optbuf, ","); | |
523 | strcat(optbuf, "DELAY"); | |
524 | firstone = FALSE; | |
525 | } | |
526 | if (firstone) | |
527 | strcat(optbuf, "NEVER"); | |
82e3dc75 | 528 | } |
82e3dc75 | 529 | |
3b6c2253 EA |
530 | /* ORCPT= parameter */ |
531 | if (to->q_orcpt != NULL) | |
532 | { | |
533 | strcat(optbuf, " ORCPT="); | |
534 | strcat(optbuf, to->q_orcpt); | |
535 | } | |
68d9129a | 536 | } |
3c6123ce | 537 | |
68d9129a | 538 | smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf); |
e6b0a75b | 539 | |
8e948497 | 540 | SmtpPhase = mci->mci_phase = "client RCPT"; |
e62e1144 | 541 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
3001ca78 | 542 | r = reply(m, mci, e, TimeOuts.to_rcpt, NULL); |
126c1099 | 543 | to->q_rstatus = newstr(SmtpReplyBuffer); |
4e1c01f9 | 544 | to->q_status = smtptodsn(r); |
3ff6d543 | 545 | if (r < 0 || REPLYTYPE(r) == 4) |
4e1c01f9 | 546 | return EX_TEMPFAIL; |
4672197a | 547 | else if (REPLYTYPE(r) == 2) |
4e1c01f9 | 548 | return EX_OK; |
977ccbaf | 549 | else if (r == 550 || r == 551 || r == 553) |
4e1c01f9 | 550 | return EX_NOUSER; |
977ccbaf | 551 | else if (r == 552 || r == 554) |
4e1c01f9 | 552 | return EX_UNAVAILABLE; |
51d9cc47 EA |
553 | |
554 | #ifdef LOG | |
68f7099c | 555 | if (LogLevel > 1) |
51d9cc47 | 556 | { |
6d3599b7 EA |
557 | syslog(LOG_CRIT, "%s: %s: SMTP RCPT protocol error: %s", |
558 | e->e_id, mci->mci_host, SmtpReplyBuffer); | |
51d9cc47 EA |
559 | } |
560 | #endif | |
561 | ||
977ccbaf | 562 | return (EX_PROTOCOL); |
3c6123ce EA |
563 | } |
564 | \f/* | |
4db45bf1 | 565 | ** SMTPDATA -- send the data and clean up the transaction. |
d2eb2478 EA |
566 | ** |
567 | ** Parameters: | |
e6b0a75b | 568 | ** m -- mailer being sent to. |
dd1fe05b | 569 | ** e -- the envelope for this message. |
d2eb2478 EA |
570 | ** |
571 | ** Returns: | |
4a4ebe09 | 572 | ** exit status corresponding to DATA command. |
d2eb2478 EA |
573 | ** |
574 | ** Side Effects: | |
e6b0a75b | 575 | ** none. |
d2eb2478 EA |
576 | */ |
577 | ||
8e5c6745 | 578 | static jmp_buf CtxDataTimeout; |
ea07b2d2 | 579 | static void datatimeout(); |
8e5c6745 | 580 | |
179d940c | 581 | int |
06771186 | 582 | smtpdata(m, mci, e) |
e6b0a75b | 583 | struct mailer *m; |
f2e44ded | 584 | register MCI *mci; |
dd1fe05b | 585 | register ENVELOPE *e; |
d2eb2478 EA |
586 | { |
587 | register int r; | |
8e5c6745 EA |
588 | register EVENT *ev; |
589 | time_t timeout; | |
d2eb2478 | 590 | |
3c6123ce EA |
591 | /* |
592 | ** Send the data. | |
4db45bf1 EA |
593 | ** First send the command and check that it is ok. |
594 | ** Then send the data. | |
595 | ** Follow it up with a dot to terminate. | |
596 | ** Finally get the results of the transaction. | |
3c6123ce EA |
597 | */ |
598 | ||
4db45bf1 | 599 | /* send the command and check ok to proceed */ |
e62e1144 | 600 | smtpmessage("DATA", m, mci); |
8e948497 | 601 | SmtpPhase = mci->mci_phase = "client DATA 354"; |
e62e1144 | 602 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
3001ca78 | 603 | r = reply(m, mci, e, TimeOuts.to_datainit, NULL); |
3ff6d543 | 604 | if (r < 0 || REPLYTYPE(r) == 4) |
c6f2ede6 EA |
605 | { |
606 | smtpquit(m, mci, e); | |
3c6123ce | 607 | return (EX_TEMPFAIL); |
c6f2ede6 | 608 | } |
4672197a | 609 | else if (r == 554) |
c6f2ede6 EA |
610 | { |
611 | smtprset(m, mci, e); | |
4672197a | 612 | return (EX_UNAVAILABLE); |
c6f2ede6 | 613 | } |
4672197a | 614 | else if (r != 354) |
c6f2ede6 | 615 | { |
51d9cc47 | 616 | #ifdef LOG |
68f7099c | 617 | if (LogLevel > 1) |
51d9cc47 | 618 | { |
6d3599b7 EA |
619 | syslog(LOG_CRIT, "%s: %s: SMTP DATA-1 protocol error: %s", |
620 | e->e_id, mci->mci_host, SmtpReplyBuffer); | |
51d9cc47 EA |
621 | } |
622 | #endif | |
c6f2ede6 | 623 | smtprset(m, mci, e); |
977ccbaf | 624 | return (EX_PROTOCOL); |
c6f2ede6 | 625 | } |
4db45bf1 | 626 | |
e532e51b EA |
627 | /* |
628 | ** Set timeout around data writes. Make it at least large | |
629 | ** enough for DNS timeouts on all recipients plus some fudge | |
630 | ** factor. The main thing is that it should not be infinite. | |
631 | */ | |
632 | ||
8e5c6745 EA |
633 | if (setjmp(CtxDataTimeout) != 0) |
634 | { | |
635 | mci->mci_errno = errno; | |
636 | mci->mci_exitstat = EX_TEMPFAIL; | |
637 | mci->mci_state = MCIS_ERROR; | |
8e5c6745 EA |
638 | syserr("451 timeout writing message to %s", mci->mci_host); |
639 | smtpquit(m, mci, e); | |
640 | return EX_TEMPFAIL; | |
641 | } | |
642 | ||
fd57f063 | 643 | timeout = e->e_msgsize / 16; |
cbc7ef2c EA |
644 | if (timeout < (time_t) 600) |
645 | timeout = (time_t) 600; | |
646 | timeout += e->e_nrcpts * 300; | |
8e5c6745 EA |
647 | ev = setevent(timeout, datatimeout, 0); |
648 | ||
c23930c0 EA |
649 | /* |
650 | ** Output the actual message. | |
651 | */ | |
652 | ||
51d448e5 EA |
653 | (*e->e_puthdr)(mci, e->e_header, e); |
654 | (*e->e_putbody)(mci, e, NULL); | |
4db45bf1 | 655 | |
c23930c0 EA |
656 | /* |
657 | ** Cleanup after sending message. | |
658 | */ | |
659 | ||
8e5c6745 EA |
660 | clrevent(ev); |
661 | ||
fe3849ea EA |
662 | if (ferror(mci->mci_out)) |
663 | { | |
664 | /* error during processing -- don't send the dot */ | |
665 | mci->mci_errno = EIO; | |
666 | mci->mci_exitstat = EX_IOERR; | |
667 | mci->mci_state = MCIS_ERROR; | |
668 | smtpquit(m, mci, e); | |
669 | return EX_IOERR; | |
670 | } | |
671 | ||
4db45bf1 | 672 | /* terminate the message */ |
06771186 | 673 | fprintf(mci->mci_out, ".%s", m->m_eol); |
8e5c6745 EA |
674 | if (TrafficLogFile != NULL) |
675 | fprintf(TrafficLogFile, "%05d >>> .\n", getpid()); | |
dc2cd20f | 676 | if (Verbose) |
b6edea3d | 677 | nmessage(">>> ."); |
4db45bf1 EA |
678 | |
679 | /* check for the results of the transaction */ | |
8e948497 | 680 | SmtpPhase = mci->mci_phase = "client DATA 250"; |
e62e1144 | 681 | setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); |
3001ca78 | 682 | r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); |
e62e1144 | 683 | if (r < 0) |
c6f2ede6 EA |
684 | { |
685 | smtpquit(m, mci, e); | |
e62e1144 | 686 | return (EX_TEMPFAIL); |
c6f2ede6 | 687 | } |
e62e1144 | 688 | mci->mci_state = MCIS_OPEN; |
614b4258 | 689 | e->e_statmsg = newstr(&SmtpReplyBuffer[4]); |
e62e1144 | 690 | if (REPLYTYPE(r) == 4) |
3c6123ce | 691 | return (EX_TEMPFAIL); |
4672197a EA |
692 | else if (r == 250) |
693 | return (EX_OK); | |
694 | else if (r == 552 || r == 554) | |
695 | return (EX_UNAVAILABLE); | |
51d9cc47 | 696 | #ifdef LOG |
68f7099c | 697 | if (LogLevel > 1) |
51d9cc47 | 698 | { |
6d3599b7 EA |
699 | syslog(LOG_CRIT, "%s: %s: SMTP DATA-2 protocol error: %s", |
700 | e->e_id, mci->mci_host, SmtpReplyBuffer); | |
51d9cc47 EA |
701 | } |
702 | #endif | |
977ccbaf | 703 | return (EX_PROTOCOL); |
d2eb2478 | 704 | } |
8e5c6745 EA |
705 | |
706 | ||
ea07b2d2 | 707 | static void |
8e5c6745 EA |
708 | datatimeout() |
709 | { | |
710 | longjmp(CtxDataTimeout, 1); | |
711 | } | |
d2eb2478 | 712 | \f/* |
e6b0a75b EA |
713 | ** SMTPQUIT -- close the SMTP connection. |
714 | ** | |
715 | ** Parameters: | |
e009f4f4 | 716 | ** m -- a pointer to the mailer. |
e6b0a75b EA |
717 | ** |
718 | ** Returns: | |
719 | ** none. | |
720 | ** | |
721 | ** Side Effects: | |
722 | ** sends the final protocol and closes the connection. | |
723 | */ | |
724 | ||
179d940c | 725 | void |
e62e1144 | 726 | smtpquit(m, mci, e) |
06771186 | 727 | register MAILER *m; |
f2e44ded | 728 | register MCI *mci; |
e62e1144 | 729 | ENVELOPE *e; |
e6b0a75b | 730 | { |
90e0e4e2 EA |
731 | bool oldSuprErrs = SuprErrs; |
732 | ||
733 | /* | |
734 | ** Suppress errors here -- we may be processing a different | |
735 | ** job when we do the quit connection, and we don't want the | |
736 | ** new job to be penalized for something that isn't it's | |
737 | ** problem. | |
738 | */ | |
739 | ||
740 | SuprErrs = TRUE; | |
e6b0a75b | 741 | |
f2e44ded | 742 | /* send the quit message if we haven't gotten I/O error */ |
e62e1144 | 743 | if (mci->mci_state != MCIS_ERROR) |
044ab67a | 744 | { |
8e948497 | 745 | SmtpPhase = "client QUIT"; |
e62e1144 | 746 | smtpmessage("QUIT", m, mci); |
3001ca78 | 747 | (void) reply(m, mci, e, TimeOuts.to_quit, NULL); |
90e0e4e2 | 748 | SuprErrs = oldSuprErrs; |
06771186 | 749 | if (mci->mci_state == MCIS_CLOSED) |
90e0e4e2 EA |
750 | { |
751 | SuprErrs = oldSuprErrs; | |
11957f11 | 752 | return; |
90e0e4e2 | 753 | } |
80482eb5 EA |
754 | } |
755 | ||
2ae0e0ed | 756 | /* now actually close the connection and pick up the zombie */ |
c1e6eba2 | 757 | (void) endmailer(mci, e, NULL); |
90e0e4e2 EA |
758 | |
759 | SuprErrs = oldSuprErrs; | |
e6b0a75b EA |
760 | } |
761 | \f/* | |
f2e44ded EA |
762 | ** SMTPRSET -- send a RSET (reset) command |
763 | */ | |
764 | ||
179d940c | 765 | void |
f2e44ded EA |
766 | smtprset(m, mci, e) |
767 | register MAILER *m; | |
768 | register MCI *mci; | |
769 | ENVELOPE *e; | |
770 | { | |
771 | int r; | |
772 | ||
8e948497 | 773 | SmtpPhase = "client RSET"; |
f2e44ded | 774 | smtpmessage("RSET", m, mci); |
3001ca78 | 775 | r = reply(m, mci, e, TimeOuts.to_rset, NULL); |
263c5860 EA |
776 | if (r < 0) |
777 | mci->mci_state = MCIS_ERROR; | |
f2e44ded | 778 | else if (REPLYTYPE(r) == 2) |
263c5860 EA |
779 | { |
780 | mci->mci_state = MCIS_OPEN; | |
781 | return; | |
782 | } | |
783 | smtpquit(m, mci, e); | |
f2e44ded EA |
784 | } |
785 | \f/* | |
c428b1b2 | 786 | ** SMTPPROBE -- check the connection state |
f2e44ded EA |
787 | */ |
788 | ||
179d940c | 789 | int |
c428b1b2 | 790 | smtpprobe(mci) |
f2e44ded EA |
791 | register MCI *mci; |
792 | { | |
793 | int r; | |
794 | MAILER *m = mci->mci_mailer; | |
795 | extern ENVELOPE BlankEnvelope; | |
796 | ENVELOPE *e = &BlankEnvelope; | |
797 | ||
8e948497 | 798 | SmtpPhase = "client probe"; |
c428b1b2 | 799 | smtpmessage("RSET", m, mci); |
3001ca78 | 800 | r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); |
5d41b806 | 801 | if (r < 0 || REPLYTYPE(r) != 2) |
f2e44ded EA |
802 | smtpquit(m, mci, e); |
803 | return r; | |
804 | } | |
805 | \f/* | |
d2eb2478 EA |
806 | ** REPLY -- read arpanet reply |
807 | ** | |
808 | ** Parameters: | |
4db45bf1 | 809 | ** m -- the mailer we are reading the reply from. |
474bc899 EA |
810 | ** mci -- the mailer connection info structure. |
811 | ** e -- the current envelope. | |
812 | ** timeout -- the timeout for reads. | |
8f4ce5a5 EA |
813 | ** pfunc -- processing function called on each line of response. |
814 | ** If null, no special processing is done. | |
d2eb2478 EA |
815 | ** |
816 | ** Returns: | |
817 | ** reply code it reads. | |
818 | ** | |
819 | ** Side Effects: | |
820 | ** flushes the mail file. | |
821 | */ | |
822 | ||
179d940c | 823 | int |
3001ca78 | 824 | reply(m, mci, e, timeout, pfunc) |
1dbda134 | 825 | MAILER *m; |
f2e44ded | 826 | MCI *mci; |
e62e1144 | 827 | ENVELOPE *e; |
3001ca78 EA |
828 | time_t timeout; |
829 | void (*pfunc)(); | |
d2eb2478 | 830 | { |
cb452ecf EA |
831 | register char *bufp; |
832 | register int r; | |
3001ca78 | 833 | bool firstline = TRUE; |
a9bac7a9 EA |
834 | char junkbuf[MAXLINE]; |
835 | ||
474bc899 EA |
836 | if (mci->mci_out != NULL) |
837 | (void) fflush(mci->mci_out); | |
42281a7d | 838 | |
9678c96d | 839 | if (tTd(18, 1)) |
42281a7d | 840 | printf("reply\n"); |
d2eb2478 | 841 | |
37eaaadb EA |
842 | /* |
843 | ** Read the input line, being careful not to hang. | |
844 | */ | |
845 | ||
cb452ecf | 846 | for (bufp = SmtpReplyBuffer;; bufp = junkbuf) |
d2eb2478 | 847 | { |
37eaaadb | 848 | register char *p; |
e62e1144 | 849 | extern time_t curtime(); |
37eaaadb | 850 | |
37eaaadb | 851 | /* actually do the read */ |
e62e1144 EA |
852 | if (e->e_xfp != NULL) |
853 | (void) fflush(e->e_xfp); /* for debugging */ | |
d0729491 EA |
854 | |
855 | /* if we are in the process of closing just give the code */ | |
06771186 | 856 | if (mci->mci_state == MCIS_CLOSED) |
d0729491 EA |
857 | return (SMTPCLOSING); |
858 | ||
bc854e30 EA |
859 | if (mci->mci_out != NULL) |
860 | fflush(mci->mci_out); | |
861 | ||
d0729491 | 862 | /* get the line from the other side */ |
8e948497 | 863 | p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); |
e62e1144 EA |
864 | mci->mci_lastuse = curtime(); |
865 | ||
d0729491 | 866 | if (p == NULL) |
ed7382d3 | 867 | { |
8e5c6745 | 868 | bool oldholderrs; |
044ab67a | 869 | |
46f6ec52 EA |
870 | /* if the remote end closed early, fake an error */ |
871 | if (errno == 0) | |
872 | # ifdef ECONNRESET | |
873 | errno = ECONNRESET; | |
f3d8f6d6 | 874 | # else /* ECONNRESET */ |
46f6ec52 | 875 | errno = EPIPE; |
f3d8f6d6 | 876 | # endif /* ECONNRESET */ |
46f6ec52 | 877 | |
474bc899 | 878 | mci->mci_errno = errno; |
6e99f903 | 879 | mci->mci_exitstat = EX_TEMPFAIL; |
8e5c6745 EA |
880 | oldholderrs = HoldErrs; |
881 | HoldErrs = TRUE; | |
882 | usrerr("451 reply: read error from %s", mci->mci_host); | |
883 | ||
9759fb92 EA |
884 | /* if debugging, pause so we can see state */ |
885 | if (tTd(18, 100)) | |
886 | pause(); | |
f2e44ded | 887 | mci->mci_state = MCIS_ERROR; |
e62e1144 | 888 | smtpquit(m, mci, e); |
a40faef5 | 889 | #if XDEBUG |
8e5c6745 EA |
890 | { |
891 | char wbuf[MAXLINE]; | |
5e3f856e EA |
892 | char *p = wbuf; |
893 | if (e->e_to != NULL) | |
894 | { | |
895 | sprintf(p, "%s... ", e->e_to); | |
896 | p += strlen(p); | |
897 | } | |
898 | sprintf(p, "reply(%s) during %s", | |
899 | mci->mci_host, SmtpPhase); | |
8e5c6745 EA |
900 | checkfd012(wbuf); |
901 | } | |
902 | #endif | |
903 | HoldErrs = oldholderrs; | |
d0729491 | 904 | return (-1); |
ed7382d3 | 905 | } |
a9bac7a9 | 906 | fixcrlf(bufp, TRUE); |
37eaaadb | 907 | |
8e5c6745 EA |
908 | /* EHLO failure is not a real error */ |
909 | if (e->e_xfp != NULL && (bufp[0] == '4' || | |
910 | (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0))) | |
d7dbe85b EA |
911 | { |
912 | /* serious error -- log the previous command */ | |
337a0030 EA |
913 | if (SmtpNeedIntro) |
914 | { | |
915 | /* inform user who we are chatting with */ | |
916 | fprintf(CurEnv->e_xfp, | |
917 | "... while talking to %s:\n", | |
918 | CurHostName); | |
919 | SmtpNeedIntro = FALSE; | |
920 | } | |
cb452ecf EA |
921 | if (SmtpMsgBuffer[0] != '\0') |
922 | fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); | |
923 | SmtpMsgBuffer[0] = '\0'; | |
d7dbe85b EA |
924 | |
925 | /* now log the message as from the other side */ | |
a9bac7a9 | 926 | fprintf(e->e_xfp, "<<< %s\n", bufp); |
d7dbe85b EA |
927 | } |
928 | ||
929 | /* display the input for verbose mode */ | |
dc2cd20f | 930 | if (Verbose) |
09bdfe00 | 931 | nmessage("050 %s", bufp); |
37eaaadb | 932 | |
3001ca78 | 933 | /* process the line */ |
0717d167 EA |
934 | if (pfunc != NULL) |
935 | (*pfunc)(bufp, firstline, m, mci, e); | |
3001ca78 EA |
936 | |
937 | firstline = FALSE; | |
938 | ||
37eaaadb | 939 | /* if continuation is required, we can go on */ |
cb452ecf EA |
940 | if (bufp[3] == '-') |
941 | continue; | |
942 | ||
943 | /* ignore improperly formated input */ | |
944 | if (!(isascii(bufp[0]) && isdigit(bufp[0]))) | |
d2eb2478 | 945 | continue; |
37eaaadb EA |
946 | |
947 | /* decode the reply code */ | |
cb452ecf | 948 | r = atoi(bufp); |
37eaaadb EA |
949 | |
950 | /* extra semantics: 0xx codes are "informational" */ | |
cb452ecf EA |
951 | if (r >= 100) |
952 | break; | |
953 | } | |
37eaaadb | 954 | |
cb452ecf EA |
955 | /* |
956 | ** Now look at SmtpReplyBuffer -- only care about the first | |
957 | ** line of the response from here on out. | |
958 | */ | |
5d41b806 | 959 | |
cb452ecf EA |
960 | /* save temporary failure messages for posterity */ |
961 | if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') | |
962 | (void) strcpy(SmtpError, SmtpReplyBuffer); | |
80482eb5 | 963 | |
cb452ecf EA |
964 | /* reply code 421 is "Service Shutting Down" */ |
965 | if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) | |
966 | { | |
967 | /* send the quit protocol */ | |
968 | mci->mci_state = MCIS_SSD; | |
969 | smtpquit(m, mci, e); | |
d2eb2478 | 970 | } |
cb452ecf EA |
971 | |
972 | return (r); | |
d2eb2478 | 973 | } |
42281a7d | 974 | \f/* |
e6b0a75b | 975 | ** SMTPMESSAGE -- send message to server |
42281a7d EA |
976 | ** |
977 | ** Parameters: | |
978 | ** f -- format | |
4db45bf1 | 979 | ** m -- the mailer to control formatting. |
42281a7d EA |
980 | ** a, b, c -- parameters |
981 | ** | |
982 | ** Returns: | |
983 | ** none. | |
984 | ** | |
985 | ** Side Effects: | |
06771186 | 986 | ** writes message to mci->mci_out. |
42281a7d EA |
987 | */ |
988 | ||
e6b0a75b | 989 | /*VARARGS1*/ |
179d940c | 990 | void |
6e99f903 EA |
991 | #ifdef __STDC__ |
992 | smtpmessage(char *f, MAILER *m, MCI *mci, ...) | |
993 | #else | |
994 | smtpmessage(f, m, mci, va_alist) | |
42281a7d | 995 | char *f; |
4db45bf1 | 996 | MAILER *m; |
f2e44ded | 997 | MCI *mci; |
6e99f903 EA |
998 | va_dcl |
999 | #endif | |
42281a7d | 1000 | { |
5229f34d EA |
1001 | VA_LOCAL_DECL |
1002 | ||
07b49560 | 1003 | VA_START(mci); |
5229f34d EA |
1004 | (void) vsprintf(SmtpMsgBuffer, f, ap); |
1005 | VA_END; | |
bc854e30 | 1006 | |
dc2cd20f | 1007 | if (tTd(18, 1) || Verbose) |
b6edea3d | 1008 | nmessage(">>> %s", SmtpMsgBuffer); |
8e5c6745 EA |
1009 | if (TrafficLogFile != NULL) |
1010 | fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), SmtpMsgBuffer); | |
06771186 | 1011 | if (mci->mci_out != NULL) |
bc854e30 | 1012 | { |
06771186 | 1013 | fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, |
f2e44ded | 1014 | m == NULL ? "\r\n" : m->m_eol); |
bc854e30 | 1015 | } |
80ec420e | 1016 | else if (tTd(18, 1)) |
0852beb8 | 1017 | { |
80ec420e | 1018 | printf("smtpmessage: NULL mci_out\n"); |
0852beb8 | 1019 | } |
42281a7d | 1020 | } |
884a20cb | 1021 | |
f3d8f6d6 | 1022 | # endif /* SMTP */ |