+if ( checks & OPTION_IGNQ
+ && pcre_exec(regex_IGNOREQUOTA, NULL, CS buf, bsize, 0,
+ PCRE_EOPT, NULL, 0) < 0)
+ checks &= ~OPTION_IGNQ;
+
+if ( checks & OPTION_CHUNKING
+ && pcre_exec(regex_CHUNKING, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
+ checks &= ~OPTION_CHUNKING;
+
+#ifndef DISABLE_PRDR
+if ( checks & OPTION_PRDR
+ && pcre_exec(regex_PRDR, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
+ checks &= ~OPTION_PRDR;
+#endif
+
+#ifdef SUPPORT_I18N
+if ( checks & OPTION_UTF8
+ && pcre_exec(regex_UTF8, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
+ checks &= ~OPTION_UTF8;
+#endif
+
+if ( checks & OPTION_DSN
+ && pcre_exec(regex_DSN, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
+ checks &= ~OPTION_DSN;
+
+if ( checks & OPTION_PIPE
+ && pcre_exec(regex_PIPELINING, NULL, CS buf, bsize, 0,
+ PCRE_EOPT, NULL, 0) < 0)
+ checks &= ~OPTION_PIPE;
+
+if ( checks & OPTION_SIZE
+ && pcre_exec(regex_SIZE, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
+ checks &= ~OPTION_SIZE;
+
+return checks;
+}
+
+
+
+/* Callback for emitting a BDAT data chunk header.
+
+If given a nonzero size, first flush any buffered SMTP commands
+then emit the command.
+
+Reap previous SMTP command responses if requested, and always reap
+the response from a previous BDAT command.
+
+Args:
+ tctx transport context
+ chunk_size value for SMTP BDAT command
+ flags
+ tc_chunk_last add LAST option to SMTP BDAT command
+ tc_reap_prev reap response to previous SMTP commands
+
+Returns: OK or ERROR
+*/
+
+static int
+smtp_chunk_cmd_callback(transport_ctx * tctx, unsigned chunk_size,
+ unsigned flags)
+{
+smtp_transport_options_block * ob =
+ (smtp_transport_options_block *)(tctx->tblock->options_block);
+smtp_context * sx = tctx->smtp_context;
+int cmd_count = 0;
+int prev_cmd_count;
+
+/* 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,
+ 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 */
+ }
+
+prev_cmd_count = cmd_count += sx->cmd_count;
+
+/* Reap responses for any previous, but not one we just emitted */
+
+if (chunk_size > 0)
+ prev_cmd_count--;
+if (sx->pending_BDAT)
+ prev_cmd_count--;
+
+if (flags & tc_reap_prev && prev_cmd_count > 0)
+ {
+ DEBUG(D_transport) debug_printf("look for %d responses"
+ " for previous pipelined cmds\n", prev_cmd_count);
+
+ switch(sync_responses(sx, prev_cmd_count, 0))
+ {
+ case 1: /* 2xx (only) => OK */
+ case 3: sx->good_RCPT = TRUE; /* 2xx & 5xx => OK & progress made */
+ case 2: sx->completed_addr = TRUE; /* 5xx (only) => progress made */
+ case 0: break; /* No 2xx or 5xx, but no probs */
+
+ case -1: /* Timeout on RCPT */
+ default: return ERROR; /* I/O error, or any MAIL/DATA error */
+ }
+ cmd_count = 1;
+ if (!sx->pending_BDAT)
+ pipelining_active = FALSE;
+ }
+
+/* Reap response for an outstanding BDAT */
+
+if (sx->pending_BDAT)
+ {
+ DEBUG(D_transport) debug_printf("look for one response for BDAT\n");
+
+ if (!smtp_read_response(&sx->inblock, sx->buffer, sizeof(sx->buffer), '2',
+ ob->command_timeout))
+ {
+ if (errno == 0 && sx->buffer[0] == '4')
+ {
+ errno = ERRNO_DATA4XX; /*XXX does this actually get used? */
+ sx->addrlist->more_errno |=
+ ((sx->buffer[1] - '0')*10 + sx->buffer[2] - '0') << 8;
+ }
+ return ERROR;
+ }
+ cmd_count--;
+ sx->pending_BDAT = FALSE;
+ pipelining_active = FALSE;
+ }
+else if (chunk_size > 0)
+ sx->pending_BDAT = TRUE;
+
+
+sx->cmd_count = cmd_count;
+return OK;
+}