+ struct timeval tv;
+ fd_set select_check;
+ FD_ZERO(&select_check);
+ FD_SET(fileno(smtp_in), &select_check);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ if (select(fileno(smtp_in) + 1, &select_check, NULL, NULL, &tv) != 0)
+ {
+ int c = (receive_getc)(GETC_BUFFER_UNLIMITED);
+ if (c != EOF) (receive_ungetc)(c); else
+ {
+ smtp_notquit_exit(US"connection-lost", NULL, NULL);
+ smtp_reply = US""; /* No attempt to send a response */
+ smtp_yield = FALSE; /* Nothing more on this connection */
+
+ /* Re-use the log line workspace */
+
+ g->ptr = 0;
+ g = string_cat(g, US"SMTP connection lost after final dot");
+ g = add_host_info_for_log(g);
+ log_write(0, LOG_MAIN, "%s", string_from_gstring(g));
+
+ /* Delete the files for this aborted message. */
+
+ Uunlink(spool_name);
+ Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H"));
+ Uunlink(spool_fname(US"msglog", message_subdir, message_id, US""));
+
+ goto TIDYUP;
+ }
+ }
+ }
+
+/* The connection has not gone away; we really are going to take responsibility
+for this message. */
+
+/* Cutthrough - had sender last-dot; assume we've sent (or bufferred) all
+ data onward by now.
+
+ Send dot onward. If accepted, wipe the spooled files, log as delivered and accept
+ the sender's dot (below).
+ If rejected: copy response to sender, wipe the spooled files, log appropriately.
+ If temp-reject: normally accept to sender, keep the spooled file - unless defer=pass
+ in which case pass temp-reject back to initiator and dump the files.
+
+ Having the normal spool files lets us do data-filtering, and store/forward on temp-reject.
+
+ XXX We do not handle queue-only, freezing, or blackholes.
+*/
+if(cutthrough.cctx.sock >= 0 && cutthrough.delivery)
+ {
+ uschar * msg = cutthrough_finaldot(); /* Ask the target system to accept the message */
+ /* Logging was done in finaldot() */
+ switch(msg[0])
+ {
+ case '2': /* Accept. Do the same to the source; dump any spoolfiles. */
+ cutthrough_done = ACCEPTED;
+ break; /* message_id needed for SMTP accept below */
+
+ case '4': /* Temp-reject. Keep spoolfiles and accept, unless defer-pass mode.
+ ... for which, pass back the exact error */
+ if (cutthrough.defer_pass) smtp_reply = string_copy_perm(msg, TRUE);
+ cutthrough_done = TMP_REJ; /* Avoid the usual immediate delivery attempt */
+ break; /* message_id needed for SMTP accept below */
+
+ default: /* Unknown response, or error. Treat as temp-reject. */
+ if (cutthrough.defer_pass) smtp_reply = US"450 Onward transmission not accepted";
+ cutthrough_done = TMP_REJ; /* Avoid the usual immediate delivery attempt */
+ break; /* message_id needed for SMTP accept below */
+
+ case '5': /* Perm-reject. Do the same to the source. Dump any spoolfiles */
+ smtp_reply = string_copy_perm(msg, TRUE); /* Pass on the exact error */
+ cutthrough_done = PERM_REJ;
+ break;
+ }
+ }
+
+#ifndef DISABLE_PRDR
+if(!smtp_reply || prdr_requested)
+#else
+if(!smtp_reply)
+#endif
+ {
+ log_write(0, LOG_MAIN |
+ (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) |
+ (LOGGING(received_sender) ? LOG_SENDER : 0),
+ "%s", g->s);
+
+ /* Log any control actions taken by an ACL or local_scan(). */
+
+ if (f.deliver_freeze) log_write(0, LOG_MAIN, "frozen by %s", frozen_by);
+ if (f.queue_only_policy) log_write(L_delay_delivery, LOG_MAIN,
+ "no immediate delivery: queued%s%s by %s",
+ *queue_name ? " in " : "", *queue_name ? CS queue_name : "",
+ queued_by);
+ }
+f.receive_call_bombout = FALSE;
+
+/* The store for the main log message can be reused */
+rcvd_log_reset_point = store_reset(rcvd_log_reset_point);
+
+/* If the message is frozen, and freeze_tell is set, do the telling. */
+
+if (f.deliver_freeze && freeze_tell && freeze_tell[0])