4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / usr.sbin / sendmail / src / usersmtp.c
CommitLineData
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 13static char sccsid[] = "@(#)usersmtp.c 8.1 (Berkeley) %G% (with SMTP)";
bee79b64 14#else
24634489 15static 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 34char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */
d0729491 35char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */
46f6ec52 36char SmtpError[MAXLINE] = ""; /* save failure error messages */
d0729491 37int SmtpPid; /* pid of mailer */
16133a1c
EA
38
39#ifdef __STDC__
40extern 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 59smtpinit(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
127tryhelo:
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
220void
221esmtp_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
246void
247helo_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
281smtpmailfrom(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 381smtprcpt(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 427smtpdata(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 519smtpquit(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
545smtprset(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 568smtpprobe(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 602reply(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__
747smtpmessage(char *f, MAILER *m, MCI *mci, ...)
748#else
749smtpmessage(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 */