From: Jeremy Harris Date: Tue, 18 Apr 2017 14:13:20 +0000 (+0100) Subject: CHUNKING: pipeline data right after the BDAT command X-Git-Tag: exim-4_90_RC1~187 X-Git-Url: https://git.exim.org/exim.git/commitdiff_plain/4e910c01eea401e36044816744691789ef4656fa CHUNKING: pipeline data right after the BDAT command --- diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 93fc3da4e..bebc9e70f 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -53,6 +53,9 @@ JH/07 Fix smtp transport use of limited max_rcpt under mua_wrapper. Previously the check for any unsuccessful recipients did not notice the limit, and erroneously found still-pending ones. +JH/08 Pipeline CHUNKING command and data together, on kernels that support + MSG_MORE. Only in-clear (not on TLS connections). + Exim version 4.89 ----------------- diff --git a/src/src/auths/cram_md5.c b/src/src/auths/cram_md5.c index 1ae38a9a6..9c89cb23c 100644 --- a/src/src/auths/cram_md5.c +++ b/src/src/auths/cram_md5.c @@ -280,7 +280,8 @@ if (!secret || !name) /* Initiate the authentication exchange and read the challenge, which arrives in base 64. */ -if (smtp_write_command(outblock, FALSE, "AUTH %s\r\n", ablock->public_name) < 0) +if (smtp_write_command(outblock, SCMD_FLUSH, "AUTH %s\r\n", + ablock->public_name) < 0) return FAIL_SEND; if (!smtp_read_response(inblock, buffer, buffsize, '3', timeout)) return FAIL; @@ -313,7 +314,7 @@ in big_buffer, but b64encode() returns its result in working store, so calling smtp_write_command(), which uses big_buffer, is OK. */ buffer[0] = 0; -if (smtp_write_command(outblock, FALSE, "%s\r\n", b64encode(big_buffer, +if (smtp_write_command(outblock, SCMD_FLUSH, "%s\r\n", b64encode(big_buffer, p - big_buffer)) < 0) return FAIL_SEND; return smtp_read_response(inblock, (uschar *)buffer, buffsize, '2', timeout) diff --git a/src/src/auths/plaintext.c b/src/src/auths/plaintext.c index 161aab6c0..32f8fd575 100644 --- a/src/src/auths/plaintext.c +++ b/src/src/auths/plaintext.c @@ -173,7 +173,7 @@ int auth_var_idx = 0; sent one by one. The first one is sent with the AUTH command; the remainder are sent in response to subsequent prompts. Each is expanded before being sent. */ -while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL) +while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size))) { int i, len, clear_len; uschar *ss = expand_string(s); @@ -184,12 +184,12 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL sending a line containing "*". Save the failed expansion string, because it is in big_buffer, and that gets used by the sending function. */ - if (ss == NULL) + if (!ss) { uschar *ssave = string_copy(s); if (!first) { - if (smtp_write_command(outblock, FALSE, "*\r\n") >= 0) + if (smtp_write_command(outblock, SCMD_FLUSH, "*\r\n") >= 0) (void) smtp_read_response(inblock, US buffer, buffsize, '2', timeout); } if (expand_string_forcedfail) @@ -208,17 +208,15 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL needed for the PLAIN mechanism. It must be doubled if really needed. */ for (i = 0; i < len; i++) - { if (ss[i] == '^') - { - if (ss[i+1] != '^') ss[i] = 0; else + if (ss[i+1] != '^') + ss[i] = 0; + else { i++; len--; memmove(ss + i, ss + i + 1, len - i); } - } - } /* The first string is attached to the AUTH command; others are sent unembellished. */ @@ -226,14 +224,14 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL if (first) { first = FALSE; - if (smtp_write_command(outblock, FALSE, "AUTH %s%s%s\r\n", + if (smtp_write_command(outblock, SCMD_FLUSH, "AUTH %s%s%s\r\n", ablock->public_name, (len == 0)? "" : " ", b64encode(ss, len)) < 0) return FAIL_SEND; } else { - if (smtp_write_command(outblock, FALSE, "%s\r\n", + if (smtp_write_command(outblock, SCMD_FLUSH, "%s\r\n", b64encode(ss, len)) < 0) return FAIL_SEND; } @@ -255,7 +253,7 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL if (text == NULL) { - if (smtp_write_command(outblock, FALSE, "*\r\n") >= 0) + if (smtp_write_command(outblock, SCMD_FLUSH, "*\r\n") >= 0) (void)smtp_read_response(inblock, US buffer, buffsize, '2', timeout); string_format(buffer, buffsize, "Too few items in client_send in %s " "authenticator", ablock->name); @@ -277,7 +275,7 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL uschar *save_bad = string_copy(buffer); if (!ob->client_ignore_invalid_base64) { - if (smtp_write_command(outblock, FALSE, "*\r\n") >= 0) + if (smtp_write_command(outblock, SCMD_FLUSH, "*\r\n") >= 0) (void)smtp_read_response(inblock, US buffer, buffsize, '2', timeout); string_format(buffer, buffsize, "Invalid base64 string in server " "response \"%s\"", save_bad); diff --git a/src/src/auths/spa.c b/src/src/auths/spa.c index 4d435a411..378d4f602 100644 --- a/src/src/auths/spa.c +++ b/src/src/auths/spa.c @@ -261,109 +261,103 @@ auth_spa_client( uschar *buffer, /* buffer for reading response */ int buffsize) /* size of buffer */ { - auth_spa_options_block *ob = - (auth_spa_options_block *)(ablock->options_block); - SPAAuthRequest request; - SPAAuthChallenge challenge; - SPAAuthResponse response; - char msgbuf[2048]; - char *domain = NULL; - char *username, *password; - - /* Code added by PH to expand the options */ - - *buffer = 0; /* Default no message when cancelled */ - - username = CS expand_string(ob->spa_username); - if (username == NULL) - { - if (expand_string_forcedfail) return CANCELLED; - string_format(buffer, buffsize, "expansion of \"%s\" failed in %s " - "authenticator: %s", ob->spa_username, ablock->name, - expand_string_message); - return ERROR; - } - - password = CS expand_string(ob->spa_password); - if (password == NULL) - { - if (expand_string_forcedfail) return CANCELLED; - string_format(buffer, buffsize, "expansion of \"%s\" failed in %s " - "authenticator: %s", ob->spa_password, ablock->name, - expand_string_message); - return ERROR; - } - - if (ob->spa_domain != NULL) - { - domain = CS expand_string(ob->spa_domain); - if (domain == NULL) - { - if (expand_string_forcedfail) return CANCELLED; - string_format(buffer, buffsize, "expansion of \"%s\" failed in %s " - "authenticator: %s", ob->spa_domain, ablock->name, - expand_string_message); - return ERROR; - } - } - - /* Original code */ - - if (smtp_write_command(outblock, FALSE, "AUTH %s\r\n", - ablock->public_name) < 0) - return FAIL_SEND; - - /* wait for the 3XX OK message */ - if (!smtp_read_response(inblock, (uschar *)buffer, buffsize, '3', timeout)) - return FAIL; - - DSPA("\n\n%s authenticator: using domain %s\n\n", - ablock->name, domain); - - spa_build_auth_request (&request, CS username, domain); - spa_bits_to_base64 (US msgbuf, (unsigned char*)&request, - spa_request_length(&request)); - - DSPA("\n\n%s authenticator: sending request (%s)\n\n", ablock->name, - msgbuf); - - /* send the encrypted password */ - if (smtp_write_command(outblock, FALSE, "%s\r\n", msgbuf) < 0) - return FAIL_SEND; - - /* wait for the auth challenge */ - if (!smtp_read_response(inblock, (uschar *)buffer, buffsize, '3', timeout)) - return FAIL; - - /* convert the challenge into the challenge struct */ - DSPA("\n\n%s authenticator: challenge (%s)\n\n", - ablock->name, buffer + 4); - spa_base64_to_bits ((char *)(&challenge), sizeof(challenge), (const char *)(buffer + 4)); - - spa_build_auth_response (&challenge, &response, - CS username, CS password); - spa_bits_to_base64 (US msgbuf, (unsigned char*)&response, - spa_request_length(&response)); - DSPA("\n\n%s authenticator: challenge response (%s)\n\n", ablock->name, - msgbuf); - - /* send the challenge response */ - if (smtp_write_command(outblock, FALSE, "%s\r\n", msgbuf) < 0) - return FAIL_SEND; - - /* If we receive a success response from the server, authentication - has succeeded. There may be more data to send, but is there any point - in provoking an error here? */ - if (smtp_read_response(inblock, US buffer, buffsize, '2', timeout)) - return OK; - - /* Not a success response. If errno != 0 there is some kind of transmission - error. Otherwise, check the response code in the buffer. If it starts with - '3', more data is expected. */ - if (errno != 0 || buffer[0] != '3') - return FAIL; - - return FAIL; +auth_spa_options_block *ob = + (auth_spa_options_block *)(ablock->options_block); +SPAAuthRequest request; +SPAAuthChallenge challenge; +SPAAuthResponse response; +char msgbuf[2048]; +char *domain = NULL; +char *username, *password; + +/* Code added by PH to expand the options */ + +*buffer = 0; /* Default no message when cancelled */ + +if (!(username = CS expand_string(ob->spa_username))) + { + if (expand_string_forcedfail) return CANCELLED; + string_format(buffer, buffsize, "expansion of \"%s\" failed in %s " + "authenticator: %s", ob->spa_username, ablock->name, + expand_string_message); + return ERROR; + } + +if (!(password = CS expand_string(ob->spa_password))) + { + if (expand_string_forcedfail) return CANCELLED; + string_format(buffer, buffsize, "expansion of \"%s\" failed in %s " + "authenticator: %s", ob->spa_password, ablock->name, + expand_string_message); + return ERROR; + } + +if (ob->spa_domain) + { + if (!(domain = CS expand_string(ob->spa_domain))) + { + if (expand_string_forcedfail) return CANCELLED; + string_format(buffer, buffsize, "expansion of \"%s\" failed in %s " + "authenticator: %s", ob->spa_domain, ablock->name, + expand_string_message); + return ERROR; + } + } + +/* Original code */ + +if (smtp_write_command(outblock, SCMD_FLUSH, "AUTH %s\r\n", + ablock->public_name) < 0) + return FAIL_SEND; + +/* wait for the 3XX OK message */ +if (!smtp_read_response(inblock, (uschar *)buffer, buffsize, '3', timeout)) + return FAIL; + +DSPA("\n\n%s authenticator: using domain %s\n\n", ablock->name, domain); + +spa_build_auth_request (&request, CS username, domain); +spa_bits_to_base64 (US msgbuf, (unsigned char*)&request, + spa_request_length(&request)); + +DSPA("\n\n%s authenticator: sending request (%s)\n\n", ablock->name, msgbuf); + +/* send the encrypted password */ +if (smtp_write_command(outblock, SCMD_FLUSH, "%s\r\n", msgbuf) < 0) + return FAIL_SEND; + +/* wait for the auth challenge */ +if (!smtp_read_response(inblock, (uschar *)buffer, buffsize, '3', timeout)) + return FAIL; + +/* convert the challenge into the challenge struct */ +DSPA("\n\n%s authenticator: challenge (%s)\n\n", ablock->name, buffer + 4); +spa_base64_to_bits ((char *)(&challenge), sizeof(challenge), (const char *)(buffer + 4)); + +spa_build_auth_response (&challenge, &response, CS username, CS password); +spa_bits_to_base64 (US msgbuf, (unsigned char*)&response, + spa_request_length(&response)); +DSPA("\n\n%s authenticator: challenge response (%s)\n\n", ablock->name, msgbuf); + +/* send the challenge response */ +if (smtp_write_command(outblock, SCMD_FLUSH, "%s\r\n", msgbuf) < 0) + return FAIL_SEND; + +/* If we receive a success response from the server, authentication +has succeeded. There may be more data to send, but is there any point +in provoking an error here? */ + +if (smtp_read_response(inblock, US buffer, buffsize, '2', timeout)) + return OK; + +/* Not a success response. If errno != 0 there is some kind of transmission +error. Otherwise, check the response code in the buffer. If it starts with +'3', more data is expected. */ + +if (errno != 0 || buffer[0] != '3') + return FAIL; + +return FAIL; } /* End of spa.c */ diff --git a/src/src/functions.h b/src/src/functions.h index ec4aba6ec..c3c96b69c 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -417,7 +417,7 @@ extern int smtp_setup_msg(void); extern BOOL smtp_start_session(void); extern int smtp_ungetc(int); extern BOOL smtp_verify_helo(void); -extern int smtp_write_command(smtp_outblock *, BOOL, const char *, ...) PRINTF_FUNCTION(3,4); +extern int smtp_write_command(smtp_outblock *, int, const char *, ...) PRINTF_FUNCTION(3,4); #ifdef WITH_CONTENT_SCAN extern int spam(const uschar **); extern FILE *spool_mbox(unsigned long *, const uschar *, uschar **); diff --git a/src/src/macros.h b/src/src/macros.h index 08f631bbb..0c1425f80 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -855,6 +855,14 @@ enum { #define topt_escape_headers 0x080 /* Apply escape check to headers */ #define topt_use_bdat 0x100 /* prepend chunks with RFC3030 BDAT header */ +/* Options for smtp_write_command */ + +enum { + SCMD_FLUSH = 0, /* write to kernel */ + SCMD_MORE, /* write to kernel, but likely more soon */ + SCMD_BUFFER /* stash in application cmd output buffer */ +}; + /* Flags for recipient_block, used in DSN support */ #define rf_dsnlasthop 0x01 /* Do not propagate DSN any further */ diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index 32382c305..7ade9ba67 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -319,23 +319,32 @@ pipelining. Argument: outblock the SMTP output block + mode more-expected, or plain Returns: TRUE if OK, FALSE on error, with errno set */ static BOOL -flush_buffer(smtp_outblock *outblock) +flush_buffer(smtp_outblock * outblock, int mode) { int rc; int n = outblock->ptr - outblock->buffer; -HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes\n", n); +HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n, + mode == SCMD_MORE ? " (with MORE annotation)" : ""); + #ifdef SUPPORT_TLS if (tls_out.active == outblock->sock) rc = tls_write(FALSE, outblock->buffer, n); else #endif - rc = send(outblock->sock, outblock->buffer, n, 0); + rc = send(outblock->sock, outblock->buffer, n, +#ifdef MSG_MORE + mode == SCMD_MORE ? MSG_MORE : 0 +#else + 0 +#endif + ); if (rc <= 0) { @@ -359,7 +368,7 @@ any error message. Arguments: outblock contains buffer for pipelining, and socket - noflush if TRUE, save the command in the output buffer, for pipelining + mode buffer, write-with-more-likely, write format a format, starting with one of of HELO, MAIL FROM, RCPT TO, DATA, ".", or QUIT. If NULL, flush pipeline buffer only. @@ -371,7 +380,7 @@ Returns: 0 if command added to pipelining buffer, with nothing transmitted */ int -smtp_write_command(smtp_outblock *outblock, BOOL noflush, const char *format, ...) +smtp_write_command(smtp_outblock * outblock, int mode, const char *format, ...) { int count; int rc = 0; @@ -393,7 +402,7 @@ if (format) if (count > outblock->buffersize - (outblock->ptr - outblock->buffer)) { rc = outblock->cmd_count; /* flush resets */ - if (!flush_buffer(outblock)) return -1; + if (!flush_buffer(outblock, SCMD_FLUSH)) return -1; } Ustrncpy(CS outblock->ptr, big_buffer, count); @@ -423,10 +432,10 @@ if (format) HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> %s\n", big_buffer); } -if (!noflush) +if (mode != SCMD_BUFFER) { rc += outblock->cmd_count; /* flush resets */ - if (!flush_buffer(outblock)) return -1; + if (!flush_buffer(outblock, mode)) return -1; } return rc; diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 997281901..f65463ea0 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -1372,13 +1372,14 @@ smtp_context * sx = tctx->smtp_context; int cmd_count = 0; int prev_cmd_count; -/* Write SMTP chunk header command */ +/* Write SMTP chunk header command. If not reaping responses, note that +there may be more writes (like, the chunk data) done soon. */ if (chunk_size > 0) { - if((cmd_count = smtp_write_command(&sx->outblock, FALSE, "BDAT %u%s\r\n", - chunk_size, - flags & tc_chunk_last ? " LAST" : "") + if((cmd_count = smtp_write_command(&sx->outblock, + flags & tc_reap_prev ? SCMD_FLUSH : SCMD_MORE, + "BDAT %u%s\r\n", chunk_size, flags & tc_chunk_last ? " LAST" : "") ) < 0) return ERROR; if (flags & tc_chunk_last) data_command = string_copy(big_buffer); /* Save for later error message */ @@ -1741,7 +1742,7 @@ goto SEND_QUIT; if (sx->esmtp) { - if (smtp_write_command(&sx->outblock, FALSE, "%s %s\r\n", + if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "%s %s\r\n", sx->lmtp ? "LHLO" : "EHLO", sx->helo_data) < 0) goto SEND_FAILED; sx->esmtp_sent = TRUE; @@ -1774,7 +1775,7 @@ goto SEND_QUIT; if (sx->esmtp_sent && (n = Ustrlen(sx->buffer)) < sizeof(sx->buffer)/2) { rsp = sx->buffer + n + 1; n = sizeof(sx->buffer) - n; } - if (smtp_write_command(&sx->outblock, FALSE, "HELO %s\r\n", sx->helo_data) < 0) + if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "HELO %s\r\n", sx->helo_data) < 0) goto SEND_FAILED; good_response = smtp_read_response(&sx->inblock, rsp, n, '2', sx->ob->command_timeout); @@ -1874,7 +1875,7 @@ if ( smtp_peer_options & PEER_OFFERED_TLS ) ) { uschar buffer2[4096]; - if (smtp_write_command(&sx->outblock, FALSE, "STARTTLS\r\n") < 0) + if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "STARTTLS\r\n") < 0) goto SEND_FAILED; /* If there is an I/O error, transmission of this message is deferred. If @@ -1988,7 +1989,7 @@ if (tls_out.active >= 0) debug_printf("not sending EHLO (host matches hosts_avoid_esmtp)\n"); } - if (smtp_write_command(&sx->outblock, FALSE, "%s %s\r\n", + if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "%s %s\r\n", sx->lmtp ? "LHLO" : greeting_cmd, sx->helo_data) < 0) goto SEND_FAILED; good_response = smtp_read_response(&sx->inblock, sx->buffer, sizeof(sx->buffer), @@ -2192,7 +2193,7 @@ FAILED: SEND_QUIT: if (sx->send_quit) - (void)smtp_write_command(&sx->outblock, FALSE, "QUIT\r\n"); + (void)smtp_write_command(&sx->outblock, SCMD_FLUSH, "QUIT\r\n"); #ifdef SUPPORT_TLS tls_close(FALSE, TRUE); @@ -2422,7 +2423,7 @@ sx->pending_MAIL = TRUE; /* The block starts with MAIL */ } #endif - rc = smtp_write_command(&sx->outblock, pipelining_active, + rc = smtp_write_command(&sx->outblock, pipelining_active ? SCMD_BUFFER : SCMD_FLUSH, "MAIL FROM:<%s>%s\r\n", s, sx->buffer); } @@ -2500,8 +2501,8 @@ for (addr = sx->first_addr, address_count = 0; } #endif - count = smtp_write_command(&sx->outblock, no_flush, "RCPT TO:<%s>%s%s\r\n", - rcpt_addr, sx->igquotstr, sx->buffer); + count = smtp_write_command(&sx->outblock, no_flush ? SCMD_BUFFER : SCMD_FLUSH, + "RCPT TO:<%s>%s%s\r\n", rcpt_addr, sx->igquotstr, sx->buffer); if (count < 0) return -5; if (count > 0) @@ -2810,7 +2811,7 @@ to send is. */ if ( !(sx.peer_offered & PEER_OFFERED_CHUNKING) && (sx.ok || (pipelining_active && !mua_wrapper))) { - int count = smtp_write_command(&sx.outblock, FALSE, "DATA\r\n"); + int count = smtp_write_command(&sx.outblock, SCMD_FLUSH, "DATA\r\n"); if (count < 0) goto SEND_FAILED; switch(sync_responses(&sx, count, sx.ok ? +1 : -1)) @@ -3337,7 +3338,7 @@ if (sx.completed_addr && sx.ok && sx.send_quit) BOOL pass_message; if (sx.send_rset) - if (! (sx.ok = smtp_write_command(&sx.outblock, FALSE, "RSET\r\n") >= 0)) + if (! (sx.ok = smtp_write_command(&sx.outblock, SCMD_FLUSH, "RSET\r\n") >= 0)) { msg = US string_sprintf("send() to %s [%s] failed: %s", host->name, host->address, strerror(errno)); @@ -3385,7 +3386,7 @@ if (sx.completed_addr && sx.ok && sx.send_quit) tls_close(FALSE, TRUE); smtp_peer_options = smtp_peer_options_wrap; sx.ok = !sx.smtps - && smtp_write_command(&sx.outblock, FALSE, + && smtp_write_command(&sx.outblock, SCMD_FLUSH, "EHLO %s\r\n", sx.helo_data) >= 0 && smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer), '2', sx.ob->command_timeout); @@ -3476,7 +3477,7 @@ This change is being made on 31-Jul-98. After over a year of trouble-free operation, the old commented-out code was removed on 17-Sep-99. */ SEND_QUIT: -if (sx.send_quit) (void)smtp_write_command(&sx.outblock, FALSE, "QUIT\r\n"); +if (sx.send_quit) (void)smtp_write_command(&sx.outblock, SCMD_FLUSH, "QUIT\r\n"); END_OFF: @@ -3557,7 +3558,7 @@ outblock.ptr = outbuffer; outblock.cmd_count = 0; outblock.authenticating = FALSE; -(void)smtp_write_command(&outblock, FALSE, "QUIT\r\n"); +(void)smtp_write_command(&outblock, SCMD_FLUSH, "QUIT\r\n"); (void)smtp_read_response(&inblock, buffer, sizeof(buffer), '2', ob->command_timeout); (void)close(inblock.sock); diff --git a/src/src/verify.c b/src/src/verify.c index 794c76c4e..de4ffbe48 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -408,7 +408,7 @@ if (addr->transport == cutthrough.addr.transport) /* Match! Send the RCPT TO, set done from the response */ done = - smtp_write_command(&ctblock, FALSE, "RCPT TO:<%.1000s>\r\n", + smtp_write_command(&ctblock, SCMD_FLUSH, "RCPT TO:<%.1000s>\r\n", transport_rcpt_address(addr, addr->transport->rcpt_include_affixes)) >= 0 && cutthrough_response(cutthrough.fd, '2', &resp, CUTTHROUGH_DATA_TIMEOUT) == '2'; @@ -804,7 +804,7 @@ tls_retry_connection: XXX We don't care about that for postmaster_full. Should we? */ if ((done = - smtp_write_command(&sx.outblock, FALSE, "RSET\r\n") >= 0 && + smtp_write_command(&sx.outblock, SCMD_FLUSH, "RSET\r\n") >= 0 && smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer), '2', callout))) break; @@ -897,7 +897,7 @@ tls_retry_connection: cancel_cutthrough_connection(TRUE, US"postmaster verify"); HDEBUG(D_acl|D_v) debug_printf_indent("Cutthrough cancelled by presence of postmaster verify\n"); - done = smtp_write_command(&sx.outblock, FALSE, "RSET\r\n") >= 0 + done = smtp_write_command(&sx.outblock, SCMD_FLUSH, "RSET\r\n") >= 0 && smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer), '2', callout); @@ -921,7 +921,7 @@ tls_retry_connection: done = TRUE; else done = (options & vopt_callout_fullpm) != 0 - && smtp_write_command(&sx.outblock, FALSE, + && smtp_write_command(&sx.outblock, SCMD_FLUSH, "RCPT TO:\r\n") >= 0 && smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer), '2', callout); @@ -1065,7 +1065,7 @@ no_conn: cancel_cutthrough_connection(TRUE, US"not usable for cutthrough"); if (sx.send_quit) { - (void) smtp_write_command(&sx.outblock, FALSE, "QUIT\r\n"); + (void) smtp_write_command(&sx.outblock, SCMD_FLUSH, "QUIT\r\n"); /* Wait a short time for response, and discard it */ smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer),