ea052b58a3a30355dc7a3201d2bfa2175e20e5d1
[exim.git] / src / src / smtp_out.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge 1995 - 2018 */
6 /* See the file NOTICE for conditions of use and distribution. */
7
8 /* A number of functions for driving outgoing SMTP calls. */
9
10
11 #include "exim.h"
12 #include "transports/smtp.h"
13
14
15
16 /*************************************************
17 *           Find an outgoing interface           *
18 *************************************************/
19
20 /* This function is called from the smtp transport and also from the callout
21 code in verify.c. Its job is to expand a string to get a list of interfaces,
22 and choose a suitable one (IPv4 or IPv6) for the outgoing address.
23
24 Arguments:
25   istring    string interface setting, may be NULL, meaning "any", in
26                which case the function does nothing
27   host_af    AF_INET or AF_INET6 for the outgoing IP address
28   addr       the mail address being handled (for setting errors)
29   interface  point this to the interface
30   msg        to add to any error message
31
32 Returns:     TRUE on success, FALSE on failure, with error message
33                set in addr and transport_return set to PANIC
34 */
35
36 BOOL
37 smtp_get_interface(uschar *istring, int host_af, address_item *addr,
38   uschar **interface, uschar *msg)
39 {
40 const uschar * expint;
41 uschar *iface;
42 int sep = 0;
43
44 if (!istring) return TRUE;
45
46 if (!(expint = expand_string(istring)))
47   {
48   if (f.expand_string_forcedfail) return TRUE;
49   addr->transport_return = PANIC;
50   addr->message = string_sprintf("failed to expand \"interface\" "
51       "option for %s: %s", msg, expand_string_message);
52   return FALSE;
53   }
54
55 while (isspace(*expint)) expint++;
56 if (*expint == 0) return TRUE;
57
58 while ((iface = string_nextinlist(&expint, &sep, big_buffer,
59           big_buffer_size)))
60   {
61   if (string_is_ip_address(iface, NULL) == 0)
62     {
63     addr->transport_return = PANIC;
64     addr->message = string_sprintf("\"%s\" is not a valid IP "
65       "address for the \"interface\" option for %s",
66       iface, msg);
67     return FALSE;
68     }
69
70   if (((Ustrchr(iface, ':') == NULL)? AF_INET:AF_INET6) == host_af)
71     break;
72   }
73
74 if (iface) *interface = string_copy(iface);
75 return TRUE;
76 }
77
78
79
80 /*************************************************
81 *           Find an outgoing port                *
82 *************************************************/
83
84 /* This function is called from the smtp transport and also from the callout
85 code in verify.c. Its job is to find a port number. Note that getservbyname()
86 produces the number in network byte order.
87
88 Arguments:
89   rstring     raw (unexpanded) string representation of the port
90   addr        the mail address being handled (for setting errors)
91   port        stick the port in here
92   msg         for adding to error message
93
94 Returns:      TRUE on success, FALSE on failure, with error message set
95                 in addr, and transport_return set to PANIC
96 */
97
98 BOOL
99 smtp_get_port(uschar *rstring, address_item *addr, int *port, uschar *msg)
100 {
101 uschar *pstring = expand_string(rstring);
102
103 if (!pstring)
104   {
105   addr->transport_return = PANIC;
106   addr->message = string_sprintf("failed to expand \"%s\" (\"port\" option) "
107     "for %s: %s", rstring, msg, expand_string_message);
108   return FALSE;
109   }
110
111 if (isdigit(*pstring))
112   {
113   uschar *end;
114   *port = Ustrtol(pstring, &end, 0);
115   if (end != pstring + Ustrlen(pstring))
116     {
117     addr->transport_return = PANIC;
118     addr->message = string_sprintf("invalid port number for %s: %s", msg,
119       pstring);
120     return FALSE;
121     }
122   }
123
124 else
125   {
126   struct servent *smtp_service = getservbyname(CS pstring, "tcp");
127   if (!smtp_service)
128     {
129     addr->transport_return = PANIC;
130     addr->message = string_sprintf("TCP port \"%s\" is not defined for %s",
131       pstring, msg);
132     return FALSE;
133     }
134   *port = ntohs(smtp_service->s_port);
135   }
136
137 return TRUE;
138 }
139
140
141
142
143 #ifdef TCP_FASTOPEN
144 static void
145 tfo_out_check(int sock)
146 {
147 # if defined(TCP_INFO) && defined(EXIM_HAVE_TCPI_UNACKED)
148 struct tcp_info tinfo;
149 socklen_t len = sizeof(tinfo);
150
151 switch (tcp_out_fastopen)
152   {
153     /* This is a somewhat dubious detection method; totally undocumented so likely
154     to fail in future kernels.  There seems to be no documented way.  What we really
155     want to know is if the server sent smtp-banner data before our ACK of his SYN,ACK
156     hit him.  What this (possibly?) detects is whether we sent a TFO cookie with our
157     SYN, as distinct from a TFO request.  This gets a false-positive when the server
158     key is rotated; we send the old one (which this test sees) but the server returns
159     the new one and does not send its SMTP banner before we ACK his SYN,ACK.
160      To force that rotation case:
161      '# echo -n "00000000-00000000-00000000-0000000" >/proc/sys/net/ipv4/tcp_fastopen_key'
162     The kernel seems to be counting unack'd packets. */
163
164   case TFO_ATTEMPTED_NODATA:
165     if (  getsockopt(sock, IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0
166        && tinfo.tcpi_state == TCP_SYN_SENT
167        && tinfo.tcpi_unacked > 1
168        )
169       {
170       DEBUG(D_transport|D_v)
171         debug_printf("TCP_FASTOPEN tcpi_unacked %d\n", tinfo.tcpi_unacked);
172       tcp_out_fastopen = TFO_USED_NODATA;
173       }
174     break;
175
176     /* When called after waiting for received data we should be able
177     to tell if data we sent was accepted. */
178
179   case TFO_ATTEMPTED_DATA:
180     if (  getsockopt(sock, IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0
181        && tinfo.tcpi_state == TCP_ESTABLISHED
182        )
183       if (tinfo.tcpi_options & TCPI_OPT_SYN_DATA)
184         {
185         DEBUG(D_transport|D_v) debug_printf("TFO: data was acked\n");
186         tcp_out_fastopen = TFO_USED_DATA;
187         }
188       else
189         {
190         DEBUG(D_transport|D_v) debug_printf("TFO: had to retransmit\n");
191         tcp_out_fastopen = TFO_NOT_USED;
192         }
193     break;
194
195   default: break; /* compiler quietening */
196   }
197 # endif
198 }
199 #endif
200
201
202 /* Arguments as for smtp_connect(), plus
203   early_data    if non-NULL, idenmpotent data to be sent -
204                 preferably in the TCP SYN segment
205
206 Returns:      connected socket number, or -1 with errno set
207 */
208
209 int
210 smtp_sock_connect(host_item * host, int host_af, int port, uschar * interface,
211   transport_instance * tb, int timeout, const blob * early_data)
212 {
213 smtp_transport_options_block * ob =
214   (smtp_transport_options_block *)tb->options_block;
215 const uschar * dscp = ob->dscp;
216 int dscp_value;
217 int dscp_level;
218 int dscp_option;
219 int sock;
220 int save_errno = 0;
221 const blob * fastopen_blob = NULL;
222
223
224 #ifndef DISABLE_EVENT
225 deliver_host_address = host->address;
226 deliver_host_port = port;
227 if (event_raise(tb->event_action, US"tcp:connect", NULL)) return -1;
228 #endif
229
230 if ((sock = ip_socket(SOCK_STREAM, host_af)) < 0) return -1;
231
232 /* Set TCP_NODELAY; Exim does its own buffering. */
233
234 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, US &on, sizeof(on)))
235   HDEBUG(D_transport|D_acl|D_v)
236     debug_printf_indent("failed to set NODELAY: %s ", strerror(errno));
237
238 /* Set DSCP value, if we can. For now, if we fail to set the value, we don't
239 bomb out, just log it and continue in default traffic class. */
240
241 if (dscp && dscp_lookup(dscp, host_af, &dscp_level, &dscp_option, &dscp_value))
242   {
243   HDEBUG(D_transport|D_acl|D_v)
244     debug_printf_indent("DSCP \"%s\"=%x ", dscp, dscp_value);
245   if (setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value)) < 0)
246     HDEBUG(D_transport|D_acl|D_v)
247       debug_printf_indent("failed to set DSCP: %s ", strerror(errno));
248   /* If the kernel supports IPv4 and IPv6 on an IPv6 socket, we need to set the
249   option for both; ignore failures here */
250   if (host_af == AF_INET6 &&
251       dscp_lookup(dscp, AF_INET, &dscp_level, &dscp_option, &dscp_value))
252     (void) setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value));
253   }
254
255 /* Bind to a specific interface if requested. Caller must ensure the interface
256 is the same type (IPv4 or IPv6) as the outgoing address. */
257
258 if (interface && ip_bind(sock, host_af, interface, 0) < 0)
259   {
260   save_errno = errno;
261   HDEBUG(D_transport|D_acl|D_v)
262     debug_printf_indent("unable to bind outgoing SMTP call to %s: %s", interface,
263     strerror(errno));
264   }
265
266 /* Connect to the remote host, and add keepalive to the socket before returning
267 it, if requested.  If the build supports TFO, request it - and if the caller
268 requested some early-data then include that in the TFO request.  If there is
269 early-data but no TFO support, send it after connecting. */
270
271 else
272   {
273 #ifdef TCP_FASTOPEN
274   if (verify_check_given_host(CUSS &ob->hosts_try_fastopen, host) == OK)
275     fastopen_blob = early_data ? early_data : &tcp_fastopen_nodata;
276 #endif
277
278   if (ip_connect(sock, host_af, host->address, port, timeout, fastopen_blob) < 0)
279     save_errno = errno;
280   else if (early_data && !fastopen_blob && early_data->data && early_data->len)
281     {
282     HDEBUG(D_transport|D_acl|D_v)
283       debug_printf("sending %ld nonTFO early-data\n", (long)early_data->len);
284
285 #ifdef TCP_QUICKACK
286     (void) setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off));
287 #endif
288     if (send(sock, early_data->data, early_data->len, 0) < 0)
289       save_errno = errno;
290     }
291   }
292
293 /* Either bind() or connect() failed */
294
295 if (save_errno != 0)
296   {
297   HDEBUG(D_transport|D_acl|D_v)
298     {
299     debug_printf_indent("failed: %s", CUstrerror(save_errno));
300     if (save_errno == ETIMEDOUT)
301       debug_printf(" (timeout=%s)", readconf_printtime(timeout));
302     debug_printf("\n");
303     }
304   (void)close(sock);
305   errno = save_errno;
306   return -1;
307   }
308
309 /* Both bind() and connect() succeeded, and any early-data */
310
311 else
312   {
313   union sockaddr_46 interface_sock;
314   EXIM_SOCKLEN_T size = sizeof(interface_sock);
315
316   HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("connected\n");
317   if (getsockname(sock, (struct sockaddr *)(&interface_sock), &size) == 0)
318     sending_ip_address = host_ntoa(-1, &interface_sock, NULL, &sending_port);
319   else
320     {
321     log_write(0, LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC),
322       "getsockname() failed: %s", strerror(errno));
323     close(sock);
324     return -1;
325     }
326
327   if (ob->keepalive) ip_keepalive(sock, host->address, TRUE);
328 #ifdef TCP_FASTOPEN
329   tfo_out_check(sock);
330 #endif
331   return sock;
332   }
333 }
334
335
336
337
338
339 void
340 smtp_port_for_connect(host_item * host, int port)
341 {
342 if (host->port != PORT_NONE)
343   {
344   HDEBUG(D_transport|D_acl|D_v)
345     debug_printf_indent("Transport port=%d replaced by host-specific port=%d\n", port,
346       host->port);
347   port = host->port;
348   }
349 else host->port = port;    /* Set the port actually used */
350 }
351
352
353 /*************************************************
354 *           Connect to remote host               *
355 *************************************************/
356
357 /* Create a socket, and connect it to a remote host. IPv6 addresses are
358 detected by checking for a colon in the address. AF_INET6 is defined even on
359 non-IPv6 systems, to enable the code to be less messy. However, on such systems
360 host->address will always be an IPv4 address.
361
362 Arguments:
363   sc          details for making connection: host, af, interface, transport
364   early_data  if non-NULL, data to be sent - preferably in the TCP SYN segment
365
366 Returns:      connected socket number, or -1 with errno set
367 */
368
369 int
370 smtp_connect(smtp_connect_args * sc, const blob * early_data)
371 {
372 int port = sc->host->port;
373 smtp_transport_options_block * ob = sc->ob;
374
375 callout_address = string_sprintf("[%s]:%d", sc->host->address, port);
376
377 HDEBUG(D_transport|D_acl|D_v)
378   {
379   uschar * s = US" ";
380   if (sc->interface) s = string_sprintf(" from %s ", sc->interface);
381 #ifdef SUPPORT_SOCKS
382   if (ob->socks_proxy) s = string_sprintf("%svia proxy ", s);
383 #endif
384   debug_printf_indent("Connecting to %s %s%s... ", sc->host->name, callout_address, s);
385   }
386
387 /* Create and connect the socket */
388
389 #ifdef SUPPORT_SOCKS
390 if (ob->socks_proxy)
391   {
392   int sock = socks_sock_connect(sc->host, sc->host_af, port, sc->interface,
393                                 sc->tblock, ob->connect_timeout);
394   
395   if (sock >= 0)
396     {
397     if (early_data && early_data->data && early_data->len)
398       if (send(sock, early_data->data, early_data->len, 0) < 0)
399         {
400         int save_errno = errno;
401         HDEBUG(D_transport|D_acl|D_v)
402           {
403           debug_printf_indent("failed: %s", CUstrerror(save_errno));
404           if (save_errno == ETIMEDOUT)
405             debug_printf(" (timeout=%s)", readconf_printtime(ob->connect_timeout));
406           debug_printf("\n");
407           }
408         (void)close(sock);
409         sock = -1;
410         errno = save_errno;
411         }
412     }
413   return sock;
414   }
415 #endif
416
417 return smtp_sock_connect(sc->host, sc->host_af, port, sc->interface,
418                           sc->tblock, ob->connect_timeout, early_data);
419 }
420
421
422 /*************************************************
423 *        Flush outgoing command buffer           *
424 *************************************************/
425
426 /* This function is called only from smtp_write_command() below. It flushes
427 the buffer of outgoing commands. There is more than one in the buffer only when
428 pipelining.
429
430 Argument:
431   outblock   the SMTP output block
432   mode       further data expected, or plain
433
434 Returns:     TRUE if OK, FALSE on error, with errno set
435 */
436
437 static BOOL
438 flush_buffer(smtp_outblock * outblock, int mode)
439 {
440 int rc;
441 int n = outblock->ptr - outblock->buffer;
442 BOOL more = mode == SCMD_MORE;
443
444 HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n,
445   more ? " (more expected)" : "");
446
447 #ifndef DISABLE_TLS
448 if (outblock->cctx->tls_ctx)
449   rc = tls_write(outblock->cctx->tls_ctx, outblock->buffer, n, more);
450 else
451 #endif
452
453   {
454   if (outblock->conn_args)
455     {
456     blob early_data = { .data = outblock->buffer, .len = n };
457
458     /* We ignore the more-flag if we're doing a connect with early-data, which
459     means we won't get BDAT+data. A pity, but wise due to the idempotency
460     requirement: TFO with data can, in rare cases, replay the data to the
461     receiver. */
462
463     if (  (outblock->cctx->sock = smtp_connect(outblock->conn_args, &early_data))
464        < 0)
465       return FALSE;
466     outblock->conn_args = NULL;
467     rc = n;
468     }
469   else
470
471     rc = send(outblock->cctx->sock, outblock->buffer, n,
472 #ifdef MSG_MORE
473               more ? MSG_MORE : 0
474 #else
475               0
476 #endif
477              );
478   }
479
480 if (rc <= 0)
481   {
482   HDEBUG(D_transport|D_acl) debug_printf_indent("send failed: %s\n", strerror(errno));
483   return FALSE;
484   }
485
486 outblock->ptr = outblock->buffer;
487 outblock->cmd_count = 0;
488 return TRUE;
489 }
490
491
492
493 /*************************************************
494 *             Write SMTP command                 *
495 *************************************************/
496
497 /* The formatted command is left in big_buffer so that it can be reflected in
498 any error message.
499
500 Arguments:
501   sx         SMTP connection, contains buffer for pipelining, and socket
502   mode       buffer, write-with-more-likely, write
503   format     a format, starting with one of
504              of HELO, MAIL FROM, RCPT TO, DATA, ".", or QUIT.
505              If NULL, flush pipeline buffer only.
506   ...        data for the format
507
508 Returns:     0 if command added to pipelining buffer, with nothing transmitted
509             +n if n commands transmitted (may still have buffered the new one)
510             -1 on error, with errno set
511 */
512
513 int
514 smtp_write_command(void * sx, int mode, const char *format, ...)
515 {
516 smtp_outblock * outblock = &((smtp_context *)sx)->outblock;
517 int rc = 0;
518
519 if (format)
520   {
521   gstring gs = { .size = big_buffer_size, .ptr = 0, .s = big_buffer };
522   va_list ap;
523
524   va_start(ap, format);
525   if (!string_vformat(&gs, FALSE, CS format, ap))
526     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong write_command in outgoing "
527       "SMTP");
528   va_end(ap);
529   string_from_gstring(&gs);
530
531   if (gs.ptr > outblock->buffersize)
532     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong write_command in outgoing "
533       "SMTP");
534
535   if (gs.ptr > outblock->buffersize - (outblock->ptr - outblock->buffer))
536     {
537     rc = outblock->cmd_count;                 /* flush resets */
538     if (!flush_buffer(outblock, SCMD_FLUSH)) return -1;
539     }
540
541   Ustrncpy(CS outblock->ptr, gs.s, gs.ptr);
542   outblock->ptr += gs.ptr;
543   outblock->cmd_count++;
544   gs.ptr -= 2; string_from_gstring(&gs); /* remove \r\n for error message */
545
546   /* We want to hide the actual data sent in AUTH transactions from reflections
547   and logs. While authenticating, a flag is set in the outblock to enable this.
548   The AUTH command itself gets any data flattened. Other lines are flattened
549   completely. */
550
551   if (outblock->authenticating)
552     {
553     uschar *p = big_buffer;
554     if (Ustrncmp(big_buffer, "AUTH ", 5) == 0)
555       {
556       p += 5;
557       while (isspace(*p)) p++;
558       while (!isspace(*p)) p++;
559       while (isspace(*p)) p++;
560       }
561     while (*p != 0) *p++ = '*';
562     }
563
564   HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP>> %s\n", big_buffer);
565   }
566
567 if (mode != SCMD_BUFFER)
568   {
569   rc += outblock->cmd_count;                /* flush resets */
570   if (!flush_buffer(outblock, mode)) return -1;
571   }
572
573 return rc;
574 }
575
576
577
578 /*************************************************
579 *          Read one line of SMTP response        *
580 *************************************************/
581
582 /* This function reads one line of SMTP response from the server host. This may
583 not be a complete response - it could be just part of a multiline response. We
584 have to use a buffer for incoming packets, because when pipelining or using
585 LMTP, there may well be more than one response in a single packet. This
586 function is called only from the one that follows.
587
588 Arguments:
589   inblock   the SMTP input block (contains holding buffer, socket, etc.)
590   buffer    where to put the line
591   size      space available for the line
592   timeout   the timeout to use when reading a packet
593
594 Returns:    length of a line that has been put in the buffer
595             -1 otherwise, with errno set
596 */
597
598 static int
599 read_response_line(smtp_inblock *inblock, uschar *buffer, int size, int timeout)
600 {
601 uschar *p = buffer;
602 uschar *ptr = inblock->ptr;
603 uschar *ptrend = inblock->ptrend;
604 client_conn_ctx * cctx = inblock->cctx;
605
606 /* Loop for reading multiple packets or reading another packet after emptying
607 a previously-read one. */
608
609 for (;;)
610   {
611   int rc;
612
613   /* If there is data in the input buffer left over from last time, copy
614   characters from it until the end of a line, at which point we can return,
615   having removed any whitespace (which will include CR) at the end of the line.
616   The rules for SMTP say that lines end in CRLF, but there are have been cases
617   of hosts using just LF, and other MTAs are reported to handle this, so we
618   just look for LF. If we run out of characters before the end of a line,
619   carry on to read the next incoming packet. */
620
621   while (ptr < ptrend)
622     {
623     int c = *ptr++;
624     if (c == '\n')
625       {
626       while (p > buffer && isspace(p[-1])) p--;
627       *p = 0;
628       inblock->ptr = ptr;
629       return p - buffer;
630       }
631     *p++ = c;
632     if (--size < 4)
633       {
634       *p = 0;                     /* Leave malformed line for error message */
635       errno = ERRNO_SMTPFORMAT;
636       return -1;
637       }
638     }
639
640   /* Need to read a new input packet. */
641
642   if((rc = ip_recv(cctx, inblock->buffer, inblock->buffersize, timeout)) <= 0)
643     {
644     DEBUG(D_deliver|D_transport|D_acl|D_v)
645       debug_printf_indent(errno ? "  SMTP(%s)<<\n" : "  SMTP(closed)<<\n",
646         strerror(errno));
647     break;
648     }
649
650   /* Another block of data has been successfully read. Set up the pointers
651   and let the loop continue. */
652
653   ptrend = inblock->ptrend = inblock->buffer + rc;
654   ptr = inblock->buffer;
655   DEBUG(D_transport|D_acl) debug_printf_indent("read response data: size=%d\n", rc);
656   }
657
658 /* Get here if there has been some kind of recv() error; errno is set, but we
659 ensure that the result buffer is empty before returning. */
660
661 *buffer = 0;
662 return -1;
663 }
664
665
666
667
668
669 /*************************************************
670 *              Read SMTP response                *
671 *************************************************/
672
673 /* This function reads an SMTP response with a timeout, and returns the
674 response in the given buffer, as a string. A multiline response will contain
675 newline characters between the lines. The function also analyzes the first
676 digit of the reply code and returns FALSE if it is not acceptable. FALSE is
677 also returned after a reading error. In this case buffer[0] will be zero, and
678 the error code will be in errno.
679
680 Arguments:
681   sx        the SMTP connection (contains input block with holding buffer,
682                 socket, etc.)
683   buffer    where to put the response
684   size      the size of the buffer
685   okdigit   the expected first digit of the response
686   timeout   the timeout to use, in seconds
687
688 Returns:    TRUE if a valid, non-error response was received; else FALSE
689 */
690 /*XXX could move to smtp transport; no other users */
691
692 BOOL
693 smtp_read_response(void * sx0, uschar * buffer, int size, int okdigit,
694    int timeout)
695 {
696 smtp_context * sx = sx0;
697 uschar * ptr = buffer;
698 int count = 0;
699
700 errno = 0;  /* Ensure errno starts out zero */
701
702 #ifdef EXPERIMENTAL_PIPE_CONNECT
703 if (sx->pending_BANNER || sx->pending_EHLO)
704   {
705   int rc;
706   if ((rc = smtp_reap_early_pipe(sx, &count)) != OK)
707     {
708     DEBUG(D_transport) debug_printf("failed reaping pipelined cmd responsess\n");
709     buffer[0] = '\0';
710     if (rc == DEFER) errno = ERRNO_TLSFAILURE;
711     return FALSE;
712     }
713   }
714 #endif
715
716 /* This is a loop to read and concatenate the lines that make up a multi-line
717 response. */
718
719 for (;;)
720   {
721   if ((count = read_response_line(&sx->inblock, ptr, size, timeout)) < 0)
722     return FALSE;
723
724   HDEBUG(D_transport|D_acl|D_v)
725     debug_printf_indent("  %s %s\n", ptr == buffer ? "SMTP<<" : "      ", ptr);
726
727   /* Check the format of the response: it must start with three digits; if
728   these are followed by a space or end of line, the response is complete. If
729   they are followed by '-' this is a multi-line response and we must look for
730   another line until the final line is reached. The only use made of multi-line
731   responses is to pass them back as error messages. We therefore just
732   concatenate them all within the buffer, which should be large enough to
733   accept any reasonable number of lines. */
734
735   if (count < 3 ||
736      !isdigit(ptr[0]) ||
737      !isdigit(ptr[1]) ||
738      !isdigit(ptr[2]) ||
739      (ptr[3] != '-' && ptr[3] != ' ' && ptr[3] != 0))
740     {
741     errno = ERRNO_SMTPFORMAT;    /* format error */
742     return FALSE;
743     }
744
745   /* If the line we have just read is a terminal line, line, we are done.
746   Otherwise more data has to be read. */
747
748   if (ptr[3] != '-') break;
749
750   /* Move the reading pointer upwards in the buffer and insert \n between the
751   components of a multiline response. Space is left for this by read_response_
752   line(). */
753
754   ptr += count;
755   *ptr++ = '\n';
756   size -= count + 1;
757   }
758
759 #ifdef TCP_FASTOPEN
760   tfo_out_check(sx->cctx.sock);
761 #endif
762
763 /* Return a value that depends on the SMTP return code. On some systems a
764 non-zero value of errno has been seen at this point, so ensure it is zero,
765 because the caller of this function looks at errno when FALSE is returned, to
766 distinguish between an unexpected return code and other errors such as
767 timeouts, lost connections, etc. */
768
769 errno = 0;
770 return buffer[0] == okdigit;
771 }
772
773 /* End of smtp_out.c */
774 /* vi: aw ai sw=2
775 */