+ if ( sx->peer_offered & PEER_OFFERED_CHUNKING
+ && verify_check_given_host(&sx->ob->hosts_try_chunking, sx->host) != OK)
+ sx->peer_offered &= ~PEER_OFFERED_CHUNKING;
+
+ if (sx->peer_offered & PEER_OFFERED_CHUNKING)
+ {DEBUG(D_transport) debug_printf("CHUNKING usable\n");}
+
+#ifndef DISABLE_PRDR
+ if ( sx->peer_offered & PEER_OFFERED_PRDR
+ && verify_check_given_host(&sx->ob->hosts_try_prdr, sx->host) != OK)
+ sx->peer_offered &= ~PEER_OFFERED_PRDR;
+
+ if (sx->peer_offered & PEER_OFFERED_PRDR)
+ {DEBUG(D_transport) debug_printf("PRDR usable\n");}
+#endif
+
+ /* Note if the server supports DSN */
+ smtp_peer_options |= sx->peer_offered & PEER_OFFERED_DSN;
+ DEBUG(D_transport) debug_printf("%susing DSN\n",
+ sx->peer_offered & PEER_OFFERED_DSN ? "" : "not ");
+
+ /* Note if the response to EHLO specifies support for the AUTH extension.
+ If it has, check that this host is one we want to authenticate to, and do
+ the business. The host name and address must be available when the
+ authenticator's client driver is running. */
+
+ switch (yield = smtp_auth(sx->buffer, sizeof(sx->buffer), sx->addrlist, sx->host,
+ sx->ob, sx->esmtp, &sx->inblock, &sx->outblock))
+ {
+ default: goto SEND_QUIT;
+ case OK: break;
+ case FAIL_SEND: goto SEND_FAILED;
+ case FAIL: goto RESPONSE_FAILED;
+ }
+ }
+ }
+pipelining_active = !!(smtp_peer_options & PEER_OFFERED_PIPE);
+
+/* The setting up of the SMTP call is now complete. Any subsequent errors are
+message-specific. */
+
+sx->setting_up = FALSE;
+
+#ifdef SUPPORT_I18N
+if (sx->addrlist->prop.utf8_msg)
+ {
+ sx->utf8_needed = !sx->addrlist->prop.utf8_downcvt
+ && !sx->addrlist->prop.utf8_downcvt_maybe;
+ DEBUG(D_transport) if (!sx->utf8_needed)
+ debug_printf("utf8: %s downconvert\n",
+ sx->addrlist->prop.utf8_downcvt ? "mandatory" : "optional");
+ }
+
+/* If this is an international message we need the host to speak SMTPUTF8 */
+if (sx->utf8_needed && !(sx->peer_offered & PEER_OFFERED_UTF8))
+ {
+ errno = ERRNO_UTF8_FWD;
+ goto RESPONSE_FAILED;
+ }
+#endif
+
+return OK;
+
+
+ {
+ int code;
+
+ RESPONSE_FAILED:
+ message = NULL;
+ sx->send_quit = check_response(sx->host, &errno, sx->addrlist->more_errno,
+ sx->buffer, &code, &message, &pass_message);
+ goto FAILED;
+
+ SEND_FAILED:
+ code = '4';
+ message = US string_sprintf("send() to %s [%s] failed: %s",
+ sx->host->name, sx->host->address, strerror(errno));
+ sx->send_quit = FALSE;
+ goto FAILED;
+
+ /* This label is jumped to directly when a TLS negotiation has failed,
+ or was not done for a host for which it is required. Values will be set
+ in message and errno, and setting_up will always be true. Treat as
+ a temporary error. */
+
+ EHLOHELO_FAILED:
+ code = '4';
+ message = string_sprintf("Remote host closed connection in response to %s"
+ " (EHLO response was: %s)", smtp_command, sx->buffer);
+ sx->send_quit = FALSE;
+ goto FAILED;
+
+#ifdef SUPPORT_TLS
+ TLS_FAILED:
+ code = '4';
+ goto FAILED;
+#endif
+
+ /* The failure happened while setting up the call; see if the failure was
+ a 5xx response (this will either be on connection, or following HELO - a 5xx
+ after EHLO causes it to try HELO). If so, fail all addresses, as this host is
+ never going to accept them. For other errors during setting up (timeouts or
+ whatever), defer all addresses, and yield DEFER, so that the host is not
+ tried again for a while. */
+
+FAILED:
+ sx->ok = FALSE; /* For when reached by GOTO */
+
+ yield = code == '5'
+#ifdef SUPPORT_I18N
+ || errno == ERRNO_UTF8_FWD
+#endif
+ ? FAIL : DEFER;
+
+ set_errno(sx->addrlist, errno, message, yield, pass_message, sx->host
+#ifdef EXPERIMENTAL_DSN_INFO
+ , sx->smtp_greeting, sx->helo_response
+#endif
+ );
+ }
+
+
+SEND_QUIT:
+
+if (sx->send_quit)
+ (void)smtp_write_command(&sx->outblock, FALSE, "QUIT\r\n");
+
+#ifdef SUPPORT_TLS
+tls_close(FALSE, TRUE);
+#endif
+
+/* Close the socket, and return the appropriate value, first setting
+works because the NULL setting is passed back to the calling process, and
+remote_max_parallel is forced to 1 when delivering over an existing connection,
+
+If all went well and continue_more is set, we shouldn't actually get here if
+there are further addresses, as the return above will be taken. However,
+writing RSET might have failed, or there may be other addresses whose hosts are
+specified in the transports, and therefore not visible at top level, in which
+case continue_more won't get set. */
+
+HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n");
+if (sx->send_quit)
+ {
+ shutdown(sx->outblock.sock, SHUT_WR);
+ if (fcntl(sx->inblock.sock, F_SETFL, O_NONBLOCK) == 0)
+ for (rc = 16; read(sx->inblock.sock, sx->inbuffer, sizeof(sx->inbuffer)) > 0 && rc > 0;)
+ rc--; /* drain socket */
+ sx->send_quit = FALSE;
+ }
+(void)close(sx->inblock.sock);
+sx->inblock.sock = sx->outblock.sock = -1;
+
+#ifndef DISABLE_EVENT
+(void) event_raise(sx->tblock->event_action, US"tcp:close", NULL);
+#endif
+
+continue_transport = NULL;
+continue_hostname = NULL;
+return yield;
+}
+
+
+
+
+/* Create the string of options that will be appended to the MAIL FROM:
+in the connection context buffer */
+
+static int
+build_mailcmd_options(smtp_context * sx, address_item * addrlist)
+{
+uschar * p = sx->buffer;
+address_item * addr;
+int address_count;
+
+*p = 0;
+
+/* If we know the receiving MTA supports the SIZE qualification,
+send it, adding something to the message size to allow for imprecision
+and things that get added en route. Exim keeps the number of lines
+in a message, so we can give an accurate value for the original message, but we
+need some additional to handle added headers. (Double "." characters don't get
+included in the count.) */
+
+if (sx->peer_offered & PEER_OFFERED_SIZE)
+ {
+ sprintf(CS p, " SIZE=%d", message_size+message_linecount+sx->ob->size_addition);
+ while (*p) p++;
+ }
+
+#ifndef DISABLE_PRDR
+/* If it supports Per-Recipient Data Reponses, and we have omre than one recipient,
+request that */
+
+sx->prdr_active = FALSE;
+if (sx->peer_offered & PEER_OFFERED_PRDR)
+ for (addr = addrlist; addr; addr = addr->next)
+ if (addr->transport_return == PENDING_DEFER)
+ {
+ for (addr = addr->next; addr; addr = addr->next)
+ if (addr->transport_return == PENDING_DEFER)
+ { /* at least two recipients to send */
+ sx->prdr_active = TRUE;
+ sprintf(CS p, " PRDR"); p += 5;
+ break;
+ }
+ break;
+ }
+#endif
+
+#ifdef SUPPORT_I18N
+/* If it supports internationalised messages, and this meesage need that,
+request it */
+
+if ( sx->peer_offered & PEER_OFFERED_UTF8
+ && addrlist->prop.utf8_msg
+ && !addrlist->prop.utf8_downcvt
+ )
+ Ustrcpy(p, " SMTPUTF8"), p += 9;
+#endif
+
+/* check if all addresses have DSN-lasthop flag; do not send RET and ENVID if so */
+for (sx->dsn_all_lasthop = TRUE, addr = addrlist, address_count = 0;
+ addr && address_count < sx->max_rcpt;
+ addr = addr->next) if (addr->transport_return == PENDING_DEFER)
+ {
+ address_count++;
+ if (!(addr->dsn_flags & rf_dsnlasthop))
+ {
+ sx->dsn_all_lasthop = FALSE;
+ break;
+ }
+ }
+
+/* Add any DSN flags to the mail command */
+
+if (sx->peer_offered & PEER_OFFERED_DSN && !sx->dsn_all_lasthop)
+ {
+ if (dsn_ret == dsn_ret_hdrs)
+ { Ustrcpy(p, " RET=HDRS"); p += 9; }
+ else if (dsn_ret == dsn_ret_full)
+ { Ustrcpy(p, " RET=FULL"); p += 9; }
+
+ if (dsn_envid)
+ {
+ string_format(p, sizeof(sx->buffer) - (p-sx->buffer), " ENVID=%s", dsn_envid);
+ while (*p) p++;
+ }
+ }
+
+/* If an authenticated_sender override has been specified for this transport
+instance, expand it. If the expansion is forced to fail, and there was already
+an authenticated_sender for this message, the original value will be used.
+Other expansion failures are serious. An empty result is ignored, but there is
+otherwise no check - this feature is expected to be used with LMTP and other
+cases where non-standard addresses (e.g. without domains) might be required. */
+
+if (smtp_mail_auth_str(p, sizeof(sx->buffer) - (p-sx->buffer), addrlist, sx->ob))
+ return ERROR;
+
+return OK;
+}
+
+
+static void
+build_rcptcmd_options(smtp_context * sx, const address_item * addr)
+{
+uschar * p = sx->buffer;
+*p = 0;
+
+/* Add any DSN flags to the rcpt command */
+
+if (sx->peer_offered & PEER_OFFERED_DSN && !(addr->dsn_flags & rf_dsnlasthop))
+ {
+ if (addr->dsn_flags & rf_dsnflags)
+ {
+ int i;
+ BOOL first = TRUE;
+
+ Ustrcpy(p, " NOTIFY=");
+ while (*p) p++;
+ for (i = 0; i < nelem(rf_list); i++) if (addr->dsn_flags & rf_list[i])
+ {
+ if (!first) *p++ = ',';
+ first = FALSE;
+ Ustrcpy(p, rf_names[i]);
+ while (*p) p++;
+ }
+ }
+
+ if (addr->dsn_orcpt)
+ {
+ string_format(p, sizeof(sx->buffer) - (p-sx->buffer), " ORCPT=%s",
+ addr->dsn_orcpt);
+ while (*p) p++;
+ }
+ }
+}
+
+
+
+/*
+Return:
+ 0 good, rcpt results in addr->transport_return (PENDING_OK, DEFER, FAIL)
+ -1 MAIL response error
+ -2 any non-MAIL read i/o error
+ -3 non-MAIL response timeout
+ -4 internal error; channel still usable
+ -5 transmit failed
+ */
+
+int
+smtp_write_mail_and_rcpt_cmds(smtp_context * sx, int * yield)
+{
+address_item * addr;
+int address_count;
+int rc;
+
+if (build_mailcmd_options(sx, sx->first_addr) != OK)
+ {
+ *yield = ERROR;
+ return -4;
+ }
+
+/* From here until we send the DATA command, we can make use of PIPELINING
+if the server host supports it. The code has to be able to check the responses
+at any point, for when the buffer fills up, so we write it totally generally.
+When PIPELINING is off, each command written reports that it has flushed the
+buffer. */
+
+sx->pending_MAIL = TRUE; /* The block starts with MAIL */
+
+ {
+ uschar * s = sx->from_addr;
+#ifdef SUPPORT_I18N
+ uschar * errstr = NULL;
+
+ /* If we must downconvert, do the from-address here. Remember we had to
+ for the to-addresses (done below), and also (ugly) for re-doing when building
+ the delivery log line. */
+
+ if ( sx->addrlist->prop.utf8_msg
+ && (sx->addrlist->prop.utf8_downcvt || !(sx->peer_offered & PEER_OFFERED_UTF8))
+ )
+ {
+ if (s = string_address_utf8_to_alabel(s, &errstr), errstr)
+ {
+ set_errno_nohost(sx->addrlist, ERRNO_EXPANDFAIL, errstr, DEFER, FALSE);
+ *yield = ERROR;
+ return -4;
+ }
+ setflag(sx->addrlist, af_utf8_downcvt);
+ }
+#endif
+
+ rc = smtp_write_command(&sx->outblock, pipelining_active,
+ "MAIL FROM:<%s>%s\r\n", s, sx->buffer);
+ }
+
+mail_command = string_copy(big_buffer); /* Save for later error message */
+
+switch(rc)
+ {
+ case -1: /* Transmission error */
+ return -5;
+
+ case +1: /* Cmd was sent */
+ if (!smtp_read_response(&sx->inblock, sx->buffer, sizeof(sx->buffer), '2',
+ sx->ob->command_timeout))
+ {
+ if (errno == 0 && sx->buffer[0] == '4')
+ {
+ errno = ERRNO_MAIL4XX;
+ sx->addrlist->more_errno |= ((sx->buffer[1] - '0')*10 + sx->buffer[2] - '0') << 8;
+ }
+ return -1;
+ }
+ sx->pending_MAIL = FALSE;
+ break;
+
+ /* otherwise zero: command queued for pipeline */
+ }
+
+/* Pass over all the relevant recipient addresses for this host, which are the
+ones that have status PENDING_DEFER. If we are using PIPELINING, we can send
+several before we have to read the responses for those seen so far. This
+checking is done by a subroutine because it also needs to be done at the end.
+Send only up to max_rcpt addresses at a time, leaving next_addr pointing to
+the next one if not all are sent.
+
+In the MUA wrapper situation, we want to flush the PIPELINING buffer for the
+last address because we want to abort if any recipients have any kind of
+problem, temporary or permanent. We know that all recipient addresses will have
+the PENDING_DEFER status, because only one attempt is ever made, and we know
+that max_rcpt will be large, so all addresses will be done at once.
+
+For verify we flush the pipeline after any (the only) rcpt address. */
+
+for (addr = sx->first_addr, address_count = 0;
+ addr && address_count < sx->max_rcpt;
+ addr = addr->next) if (addr->transport_return == PENDING_DEFER)
+ {
+ int count;
+ BOOL no_flush;
+ uschar * rcpt_addr;
+
+ addr->dsn_aware = sx->peer_offered & PEER_OFFERED_DSN
+ ? dsn_support_yes : dsn_support_no;
+
+ address_count++;
+ no_flush = pipelining_active && !sx->verify && (!mua_wrapper || addr->next);
+
+ build_rcptcmd_options(sx, addr);
+
+ /* Now send the RCPT command, and process outstanding responses when
+ necessary. After a timeout on RCPT, we just end the function, leaving the
+ yield as OK, because this error can often mean that there is a problem with
+ just one address, so we don't want to delay the host. */
+
+ rcpt_addr = transport_rcpt_address(addr, sx->tblock->rcpt_include_affixes);
+
+#ifdef SUPPORT_I18N
+ if ( testflag(sx->addrlist, af_utf8_downcvt)
+ && !(rcpt_addr = string_address_utf8_to_alabel(rcpt_addr, NULL))
+ )
+ {
+ /*XXX could we use a per-address errstr here? Not fail the whole send? */
+ errno = ERRNO_EXPANDFAIL;
+ return -5; /*XXX too harsh? */
+ }
+#endif
+
+ count = smtp_write_command(&sx->outblock, no_flush, "RCPT TO:<%s>%s%s\r\n",
+ rcpt_addr, sx->igquotstr, sx->buffer);
+
+ if (count < 0) return -5;
+ if (count > 0)
+ {
+ switch(sync_responses(sx, count, 0))
+ {
+ case 3: sx->ok = TRUE; /* 2xx & 5xx => OK & progress made */
+ case 2: sx->completed_addr = TRUE; /* 5xx (only) => progress made */
+ break;
+
+ case 1: sx->ok = TRUE; /* 2xx (only) => OK, but if LMTP, */
+ if (!sx->lmtp) /* can't tell about progress yet */
+ sx->completed_addr = TRUE;
+ case 0: /* No 2xx or 5xx, but no probs */
+ break;
+
+ case -1: return -3; /* Timeout on RCPT */
+ case -2: return -2; /* non-MAIL read i/o error */
+ default: return -1; /* any MAIL error */
+ }
+ sx->pending_MAIL = FALSE; /* Dealt with MAIL */
+ }
+ } /* Loop for next address */
+
+sx->next_addr = addr;
+return 0;
+}
+
+
+/*************************************************
+* Deliver address list to given host *
+*************************************************/
+
+/* If continue_hostname is not null, we get here only when continuing to
+deliver down an existing channel. The channel was passed as the standard
+input. TLS is never active on a passed channel; the previous process always
+closes it down before passing the connection on.
+
+Otherwise, we have to make a connection to the remote host, and do the
+initial protocol exchange.
+
+When running as an MUA wrapper, if the sender or any recipient is rejected,
+temporarily or permanently, we force failure for all recipients.
+
+Arguments:
+ addrlist chain of potential addresses to deliver; only those whose
+ transport_return field is set to PENDING_DEFER are currently
+ being processed; others should be skipped - they have either
+ been delivered to an earlier host or IP address, or been
+ failed by one of them.
+ host host to deliver to
+ host_af AF_INET or AF_INET6
+ port default TCP/IP port to use, in host byte order
+ interface interface to bind to, or NULL
+ tblock transport instance block
+ message_defer set TRUE if yield is OK, but all addresses were deferred
+ because of a non-recipient, non-host failure, that is, a
+ 4xx response to MAIL FROM, DATA, or ".". This is a defer
+ that is specific to the message.
+ suppress_tls if TRUE, don't attempt a TLS connection - this is set for
+ a second attempt after TLS initialization fails
+
+Returns: OK - the connection was made and the delivery attempted;
+ the result for each address is in its data block.
+ DEFER - the connection could not be made, or something failed
+ while setting up the SMTP session, or there was a
+ non-message-specific error, such as a timeout.
+ ERROR - a filter command is specified for this transport,
+ and there was a problem setting it up; OR helo_data
+ or add_headers or authenticated_sender is specified
+ for this transport, and the string failed to expand
+*/
+
+static int
+smtp_deliver(address_item *addrlist, host_item *host, int host_af, int port,
+ uschar *interface, transport_instance *tblock,
+ BOOL *message_defer, BOOL suppress_tls)
+{
+address_item *addr;
+int yield = OK;
+int save_errno;
+int rc;
+time_t start_delivery_time = time(NULL);