diff --git a/src/sbbs3/sbbsexec.c b/src/sbbs3/sbbsexec.c
index 4beeed2d605c387cdf4f48697f6f52ada16b7299..be1c3f51738914e144cd12f7050438c5b1395f17 100644
--- a/src/sbbs3/sbbsexec.c
+++ b/src/sbbs3/sbbsexec.c
@@ -39,22 +39,37 @@
 #define READ_TIMEOUT			(30 * 1000)	// X00REF.DOC "the timeout value is set to 30 seconds"
 
 /* UART Parameters and virtual registers */
-WORD uart_io_base				= UART_COM1_IO_BASE;	/* COM1 */
-BYTE uart_irq					= UART_COM1_IRQ;
-BYTE uart_ier_reg				= 0;
-BYTE uart_lcr_reg				= UART_LCR_8_DATA_BITS;
-BYTE uart_mcr_reg				= UART_MCR_DTR;
-BYTE uart_lsr_reg				= UART_LSR_EMPTY_DATA | UART_LSR_EMPTY_XMIT;
-BYTE uart_msr_reg				= UART_MSR_CTS | UART_MSR_DSR;
-BYTE uart_scratch_reg			= 0;
-BYTE uart_divisor_latch_lsb		= 0x03;	/* 38400 */
-BYTE uart_divisor_latch_msb		= 0x00;
-BYTE uart_fifo_enabled			= 0;
+struct uart {
+	WORD io_base;
+	BYTE irq;
+	BYTE ier_reg;
+	BYTE lcr_reg;
+	BYTE mcr_reg;
+	BYTE lsr_reg;
+	BYTE msr_reg;
+	BYTE scratch_reg;
+	BYTE divisor_latch_lsb;
+	BYTE divisor_latch_msb;
+	BYTE fifo_enabled;
+	BOOL virtualize;
+} default_uart = {
+	.io_base				= UART_COM1_IO_BASE,	/* COM1 */
+	.irq					= UART_COM1_IRQ,
+	.ier_reg				= 0,
+	.lcr_reg				= UART_LCR_8_DATA_BITS,
+	.mcr_reg				= UART_MCR_DTR,
+	.lsr_reg				= UART_LSR_EMPTY_DATA | UART_LSR_EMPTY_XMIT,
+	.msr_reg				= UART_MSR_CTS | UART_MSR_DSR,
+	.scratch_reg			= 0,
+	.divisor_latch_lsb		= 0x03,	/* 38400 */
+	.divisor_latch_msb		= 0x00,
+	.fifo_enabled			= 0,
+	.virtualize				= FALSE
+}, uart;
 
 // Notice: re-initialize global variables in VDDInitialize for NTVDMx64 and pre-Vista versions of Windows
 int log_level = LOG_INFO;
 
-BOOL		virtualize_uart=FALSE;
 double		yield_interval=1.0;
 BOOL		dcd_changed = FALSE;
 BOOL		hangup_supported=TRUE;
@@ -125,27 +140,27 @@ void parse_ini(char* program)
 	else
 		SAFEPRINTF(section,"%s.UART",program);
 
-	virtualize_uart=iniGetBool(ini,section,"Virtualize",virtualize_uart);
+	uart.virtualize=iniGetBool(ini,section,"Virtualize",uart.virtualize);
 	switch(iniGetInteger(ini,section,"ComPort",0)) {
 		case 1:	/* COM1 */
-			uart_irq		=UART_COM1_IRQ;
-			uart_io_base	=UART_COM1_IO_BASE;
+			uart.irq		=UART_COM1_IRQ;
+			uart.io_base	=UART_COM1_IO_BASE;
 			break;
 		case 2:	/* COM2 */
-			uart_irq		=UART_COM2_IRQ;
-			uart_io_base	=UART_COM2_IO_BASE;
+			uart.irq		=UART_COM2_IRQ;
+			uart.io_base	=UART_COM2_IO_BASE;
 			break;
 		case 3:	/* COM3 */
-			uart_irq		=UART_COM3_IRQ;
-			uart_io_base	=UART_COM3_IO_BASE;
+			uart.irq		=UART_COM3_IRQ;
+			uart.io_base	=UART_COM3_IO_BASE;
 			break;
 		case 4:	/* COM4 */
-			uart_irq		=UART_COM4_IRQ;
-			uart_io_base	=UART_COM4_IO_BASE;
+			uart.irq		=UART_COM4_IRQ;
+			uart.io_base	=UART_COM4_IO_BASE;
 			break;
 	}
-	uart_irq=(BYTE)iniGetShortInt(ini,section,"IRQ",uart_irq);
-	uart_io_base=iniGetShortInt(ini,section,"Address",uart_io_base);
+	uart.irq=(BYTE)iniGetShortInt(ini,section,"IRQ",uart.irq);
+	uart.io_base=iniGetShortInt(ini,section,"Address",uart.io_base);
 
 	lprintf(LOG_INFO,"Parsed %s section of %s"
 		,section
@@ -163,9 +178,9 @@ void set_interrupt_pending(BYTE intr, BOOL assert)
 	lprintf(LOG_DEBUG,"%sasserting interrupt %02X (pending: %02X, IER: %02X)"
 		,assert ? "" : "de-", intr
 		,pending_interrupts
-		,uart_ier_reg);
+		,uart.ier_reg);
 	if(assert) {
-		if(uart_ier_reg&intr) {					/* is interrupt enabled? */
+		if(uart.ier_reg&intr) {					/* is interrupt enabled? */
 			pending_interrupts |= intr;			/* flag as pending */
 			SetEvent(interrupt_event);
 		}
@@ -180,15 +195,15 @@ void set_interrupt_pending(BYTE intr, BOOL assert)
 
 void data_waiting(BOOL waiting)
 {
-	if(waiting && (uart_mcr_reg & UART_MCR_RTS)) {
+	if(waiting && (uart.mcr_reg & UART_MCR_RTS)) {
 		/* Set the "Data ready" bit in the LSR */
-		uart_lsr_reg |= UART_LSR_DATA_READY;
+		uart.lsr_reg |= UART_LSR_DATA_READY;
 
 		/* assert rx data interrupt */
 		assert_interrupt(UART_IER_RX_DATA); 
 	} else {
 		/* Clear the data ready bit in the LSR */
-		uart_lsr_reg &= ~UART_LSR_DATA_READY;
+		uart.lsr_reg &= ~UART_LSR_DATA_READY;
 
 		/* Clear data ready interrupt identification in IIR */
 		deassert_interrupt(UART_IER_RX_DATA);
@@ -211,17 +226,17 @@ void _cdecl interrupt_thread(void *arg)
 			lprintf(LOG_NOTICE, "Waiting for interrupt returned %ld", result);
 			break;
 		}
-		if((uart_ier_reg&pending_interrupts) != 0) {
+		if((uart.ier_reg&pending_interrupts) != 0) {
 			lprintf(LOG_DEBUG,"VDDSimulateInterrupt (pending: %02X) - IER: %02X"
-				,pending_interrupts, uart_ier_reg);
-			VDDSimulateInterrupt(ICA_MASTER, uart_irq, /* count: */1);
+				,pending_interrupts, uart.ier_reg);
+			VDDSimulateInterrupt(ICA_MASTER, uart.irq, /* count: */1);
 		}
 #if 0
 		/* "Real 16550s should always reassert
 		 *  this interrupt whenever the transmitter is idle and
 		 *  the interrupt is enabled."
 		 */
-		if(pending_interrupts==0 && uart_ier_reg&UART_IER_TX_EMPTY)
+		if(pending_interrupts==0 && uart.ier_reg&UART_IER_TX_EMPTY)
 			assert_interrupt(UART_IER_TX_EMPTY);
 #endif
 	}
@@ -257,7 +272,7 @@ void _cdecl input_thread(void* arg)
 		}
 		RingBufWrite(&rdbuf,buf,count);
 
-		if(virtualize_uart) {
+		if(uart.virtualize) {
 			data_waiting(TRUE);
 		}
 	}
@@ -325,15 +340,15 @@ static char *chr(uchar ch)
 
 VOID uart_wrport(WORD port, BYTE data)
 {
-	int reg = port - uart_io_base;
+	int reg = port - uart.io_base;
 	int retval;
 
 	lprintf(LOG_DEBUG,"write of port: %x (%s) <- %02X", port, uart_reg_desc[reg], data);
 
 	switch(reg) {
 		case UART_BASE:
-			if(uart_lcr_reg&UART_LCR_DLAB) {
-				uart_divisor_latch_lsb = data;
+			if(uart.lcr_reg&UART_LCR_DLAB) {
+				uart.divisor_latch_lsb = data;
 				lprintf(LOG_DEBUG,"set divisor latch low byte: %02X", data);
 			} else { // Transmitter Holding Register
 				if(log_level >= LOG_DEBUG)
@@ -348,32 +363,32 @@ VOID uart_wrport(WORD port, BYTE data)
 			}
 			break;
 		case UART_IER:
-			if(uart_lcr_reg&UART_LCR_DLAB) {
-				uart_divisor_latch_msb = data;
+			if(uart.lcr_reg&UART_LCR_DLAB) {
+				uart.divisor_latch_msb = data;
 				lprintf(LOG_DEBUG,"set divisor latch high byte: %02X", data);
 			} else {
-				uart_ier_reg = data;
+				uart.ier_reg = data;
 				lprintf(LOG_DEBUG, "Set IER to %02X", data);
 			}
 			assert_interrupt(UART_IER_TX_EMPTY);	/* should this be re-asserted for all writes? */
 			break;
 		case UART_FCR:
-			uart_fifo_enabled = data & UART_FCR_ENABLE_FIFO;
+			uart.fifo_enabled = data & UART_FCR_ENABLE_FIFO;
 			lprintf(LOG_INFO, "Set FCR to %02X", data);
 			break;
 		case UART_LCR:
-			uart_lcr_reg = data;
+			uart.lcr_reg = data;
 			lprintf(LOG_INFO, "Set LCR to %02X", data);
 			break;
 		case UART_MCR:
-			uart_mcr_reg = data;
-			if((uart_mcr_reg&UART_MCR_DTR) == 0)	/* Dropping DTR (i.e. "hangup") */
+			uart.mcr_reg = data;
+			if((uart.mcr_reg&UART_MCR_DTR) == 0)	/* Dropping DTR (i.e. "hangup") */
 				hangup();
 			data_waiting(RingBufFull(&rdbuf));
 			lprintf(LOG_INFO, "Set MCR to %02X", data);
 			break;
 		case UART_SCRATCH:
-			uart_scratch_reg = data;
+			uart.scratch_reg = data;
 			lprintf(LOG_INFO, "Set scratch register to %02X", data);
 			break;
 		default:
@@ -385,16 +400,16 @@ VOID uart_wrport(WORD port, BYTE data)
 
 VOID uart_rdport(WORD port, PBYTE data)
 {
-	int reg = port - uart_io_base;
+	int reg = port - uart.io_base;
 	DWORD avail;
 
 	lprintf(LOG_DEBUG,"read of port: %x (%s)", port, uart_reg_desc[reg]);
 
 	switch(reg) {
 		case UART_BASE:
-			if(uart_lcr_reg&UART_LCR_DLAB) {
+			if(uart.lcr_reg&UART_LCR_DLAB) {
 				lputs(LOG_DEBUG,"reading divisor latch LSB");
-				*data = uart_divisor_latch_lsb;
+				*data = uart.divisor_latch_lsb;
 				break;
 			}
 			if((avail=RingBufFull(&rdbuf))!=0) {
@@ -407,11 +422,11 @@ VOID uart_rdport(WORD port, PBYTE data)
 			data_waiting(avail);
 			break;
 		case UART_IER:
-			if(uart_lcr_reg&UART_LCR_DLAB) {
+			if(uart.lcr_reg&UART_LCR_DLAB) {
 				lputs(LOG_DEBUG,"reading divisor latch MSB");
-				*data = uart_divisor_latch_msb;
+				*data = uart.divisor_latch_msb;
 			} else
-				*data = uart_ier_reg;
+				*data = uart.ier_reg;
 			break;
 		case UART_IIR:
 		{
@@ -432,42 +447,42 @@ VOID uart_rdport(WORD port, PBYTE data)
 				*data = UART_IIR_NONE;
 			if(pending_interrupts)
 				SetEvent(interrupt_event);
-			if(uart_fifo_enabled)
+			if(uart.fifo_enabled)
 				*data |= UART_IIR_FIFO_ENABLED;
 			lprintf(LOG_DEBUG, "IIR: %02X (pending: %02X)", *data, pending_interrupts);
 			break;
 		}
 		case UART_LCR:
-			*data = uart_lcr_reg;
-			lprintf(LOG_INFO, "LCR: %02X", uart_lcr_reg);
+			*data = uart.lcr_reg;
+			lprintf(LOG_INFO, "LCR: %02X", uart.lcr_reg);
 			break;
 		case UART_MCR:
-			*data = uart_mcr_reg;
-			lprintf(LOG_INFO, "MCR: %02X", uart_mcr_reg);
+			*data = uart.mcr_reg;
+			lprintf(LOG_INFO, "MCR: %02X", uart.mcr_reg);
 			break;
 		case UART_LSR:
-			*data = uart_lsr_reg;
+			*data = uart.lsr_reg;
 			/* Clear line status interrupt pending */
 			deassert_interrupt(UART_IER_LINE_STATUS);
 			lprintf(LOG_DEBUG, "LSR: %02X", *data);
 			break;
 		case UART_MSR:
 			if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0)
-				uart_msr_reg &= ~UART_MSR_DCD;
+				uart.msr_reg &= ~UART_MSR_DCD;
 			else
-				uart_msr_reg |= UART_MSR_DCD;
+				uart.msr_reg |= UART_MSR_DCD;
 			if(dcd_changed)
-				uart_msr_reg |= UART_MSR_DCD_CHANGE;
+				uart.msr_reg |= UART_MSR_DCD_CHANGE;
 			else
-				uart_msr_reg &= ~UART_MSR_DCD_CHANGE;
+				uart.msr_reg &= ~UART_MSR_DCD_CHANGE;
 			dcd_changed = FALSE;
-			*data = uart_msr_reg;
+			*data = uart.msr_reg;
 			/* Clear modem status interrupt pending */
 			deassert_interrupt(UART_IER_MODEM_STATUS);
 			lprintf(LOG_DEBUG, "MSR: %02X", *data);
 			break;
 		case UART_SCRATCH:
-			*data = uart_scratch_reg;
+			*data = uart.scratch_reg;
 			break;
 		default:
 			lprintf(LOG_ERR,"UNSUPPORTED register: %u", reg);
@@ -589,14 +604,14 @@ __declspec(dllexport) void __cdecl VDDDispatch(void)
 
 			lprintf(LOG_INFO,"Yield interval: %f milliseconds", yield_interval);
 
-			if(virtualize_uart) {
+			if(uart.virtualize) {
 				lprintf(LOG_INFO,"Virtualizing UART (0x%x, IRQ %u)"
-					,uart_io_base, uart_irq);
+					,uart.io_base, uart.irq);
 
 				IOHandlers.inb_handler = uart_rdport;
 				IOHandlers.outb_handler = uart_wrport;
-				PortRange.First=uart_io_base;
-				PortRange.Last=uart_io_base + UART_IO_RANGE;
+				PortRange.First=uart.io_base;
+				PortRange.Last=uart.io_base + UART_IO_RANGE;
 
 				VDDInstallIOHook((HANDLE)getAX(), 1, &PortRange, &IOHandlers);
 
@@ -626,7 +641,7 @@ __declspec(dllexport) void __cdecl VDDDispatch(void)
 			lprintf(LOG_INFO,"           read=%u bytes (in %u calls)",bytes_read,reads);
 			lprintf(LOG_INFO,"           wrote=%u bytes (in %u calls)",bytes_written,writes);
 
-			if(virtualize_uart) {
+			if(uart.virtualize) {
 				lputs(LOG_INFO,"Uninstalling Virtualizaed UART IO Hook");
 				VDDDeInstallIOHook((HANDLE)getAX(), 1, &PortRange);
 				DeleteCriticalSection(&interrupt_mutex);
@@ -857,7 +872,8 @@ __declspec(dllexport) void __cdecl VDDDispatch(void)
 		case VDD_LOAD_INI_SECTION:	/* Parse (program-specific) sub-section of settings file */
 			count = getCX();
 			p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI())
-				,count,FALSE); 
+				,count,FALSE);
+			lprintf(LOG_INFO, "LOAD_INI_SECTION: %s", p);
 			parse_ini(p);
 			break;
 
@@ -873,7 +889,7 @@ __declspec(dllexport) void __cdecl VDDDispatch(void)
 			break;
 
 		case VDD_VIRTUALIZE_UART:
-			virtualize_uart = TRUE;
+			uart.virtualize = TRUE;
 			break;
 
 		default:
@@ -886,6 +902,7 @@ __declspec(dllexport) void __cdecl VDDDispatch(void)
 __declspec(dllexport) BOOL __cdecl VDDInitialize(IN PVOID hVDD, IN ULONG Reason,	 
 IN PCONTEXT Context OPTIONAL)	 
 {
+	memcpy(&uart, &default_uart, sizeof(uart));
 	log_level = LOG_INFO;
 	lputs(LOG_INFO, __FUNCTION__);
 	return TRUE;	 
diff --git a/src/vdmodem/vdmodem.c b/src/vdmodem/vdmodem.c
index 934905e5e4abb27d841e6b194d2721fe115cbb23..ea5f9b38d7daa3a96a410205268d422943b744c1 100644
--- a/src/vdmodem/vdmodem.c
+++ b/src/vdmodem/vdmodem.c
@@ -34,6 +34,7 @@
 #include "sockwrap.h"
 #include "telnet.h"
 #include "ini_file.h"
+#include "vdd_func.h"
 #include "git_branch.h"
 #include "git_hash.h"
 
@@ -62,7 +63,7 @@ struct {
 	uint cmdlen;
 	uchar cmd[64];
 } telnet;
-
+unsigned int sbbsexec_mode = SBBSEXEC_MODE_UNSPECIFIED;
 #define XTRN_IO_BUF_LEN 10000
 #define RING_DELAY 6000 /* US standard is 6 seconds */
 
@@ -75,6 +76,7 @@ struct {
 	ulong data_rate;
 	bool server_echo;
 	char busy_notice[INI_MAX_VALUE_LEN];
+	char answer_banner[INI_MAX_VALUE_LEN];
 	enum {
 		 ADDRESS_FAMILY_UNSPEC
 		,ADDRESS_FAMILY_INET
@@ -107,6 +109,7 @@ void usage(const char* progname)
 		"\t-l[addr]  Listen for incoming TCP connections\n"
 		"\t          [on optionally-specified network interface]\n"
 		"\t-p<port>  Specify default TCP port number (decimal)\n"
+		"\t-n<node>  Specify node number\n"
 		"\t-d        Enable debug output\n"
 		"\t-h<sock>  Specify socket descriptor/handle to use (decimal)\n"
 		"\t-r<cps>   Specify maximum receive data rate (chars/second)\n"
@@ -168,6 +171,8 @@ ulong count_esc(struct modem* modem, uint8_t* buf, size_t rd)
 	for(size_t i = 0; i < rd; i++) {
 		if(buf[i] == modem->esc)
 			count++;
+		else
+			return 0;
 	}
 	return count;
 }
@@ -214,9 +219,9 @@ char* response(struct modem* modem, enum modem_response code)
 	if(modem->quiet)
 		return "";
 	if(modem->numeric_mode)
-		sprintf(str, "%u%c", code, modem->cr);
+		safe_snprintf(str, sizeof(str), "%u%c", code, modem->cr);
 	else
-		sprintf(str, "%c%c%s%c%c", modem->cr, modem->lf, response_str[code], modem->cr, modem->lf);
+		safe_snprintf(str, sizeof(str), "%c%c%s%c%c", modem->cr, modem->lf, response_str[code], modem->cr, modem->lf);
 	return str;
 }
 
@@ -353,13 +358,18 @@ const char* protocol(enum mode mode)
 	return "Raw";
 }
 
-int address_family()
+int address_family(BOOL for_listen)
 {
 	switch(cfg.address_family) {
 		case ADDRESS_FAMILY_INET:	return PF_INET;
 		case ADDRESS_FAMILY_INET6:	return PF_INET6;
 	}
-	return PF_UNSPEC;
+	return for_listen ? PF_INET : PF_UNSPEC;
+}
+
+int listen_address_family()
+{
+	return address_family(true);
 }
 
 int putcom(char* buf, size_t len)
@@ -574,24 +584,19 @@ char* dial(struct modem* modem, const char* number)
 	char* p = strrchr(host, ':');
 	char* b = strrchr(host, ']'); 
 	if(p != NULL && p > b) {
-		port = (uint16_t)strtol(p, &p, 10);
+		port = (uint16_t)strtol(p + 1, NULL, 10);
 		*p = 0;
 	}
 	dprintf("Connecting to port %hu at host '%s' via %s", port, host, protocol(mode));
 	memset(&hints, 0, sizeof(hints));
-	hints.ai_flags=PF_UNSPEC;
-	hints.ai_family=address_family();
+	hints.ai_family = address_family(/* for listen: */false);
 	hints.ai_socktype=SOCK_STREAM;
 	hints.ai_protocol=IPPROTO_TCP;
-	hints.ai_flags=AI_NUMERICSERV;
-#ifdef AI_ADDRCONFIG
-	hints.ai_flags|=AI_ADDRCONFIG;
-#endif
 	dprintf("%s %d calling getaddrinfo", __FILE__, __LINE__);
 	SAFEPRINTF(portnum, "%hu", port);
 	int result = getaddrinfo(host, portnum, &hints, &res);
 	if(result != 0) {
-		dprintf("getaddrinfo(%s, %s) returned %d", host, portnum, result);
+		dprintf("getaddrinfo(%s, %s) [family=%d] returned %d", host, portnum, hints.ai_family, result);
 		return response(modem, NO_ANSWER);
 	}
 
@@ -699,6 +704,7 @@ char* answer(struct modem* modem)
 		/* Will suppress Go Ahead */
 		request_telnet_opt(TELNET_WILL,TELNET_SUP_GA);
 	}
+	putcom(cfg.answer_banner, strlen(cfg.answer_banner));
 	return connected(modem);
 }
 
@@ -725,17 +731,18 @@ char* atmodem_exec(struct modem* modem)
 							return error(modem);
 						if(*p == '=') {
 							p++;
-							if(strcmp(p, "L") == 0)
+							if(stricmp(p, "L") == 0)
 								p = modem->last;
 							SAFECOPY(modem->save[val], p);
 							return write_save(modem, val) ? ok(modem) : error(modem);
 						}
-						if(*p == '?' || strcmp(p, "L?") == 0) {
-							if(strcmp(p, "L?") == 0)
+						if(*p == '?' || stricmp(p, "L?") == 0) {
+							if(stricmp(p, "L?") == 0)
 								p = modem->last;
 							else
 								p = modem->save[val];
-							sprintf(respbuf, "%c%s%c%c%s", modem->lf, p, modem->cr, modem->lf, ok(modem));
+							safe_snprintf(respbuf, sizeof(respbuf), "%c%s%c%c%s"
+								,modem->lf, p, modem->cr, modem->lf, ok(modem));
 							return respbuf;
 						}
 				}
@@ -854,7 +861,8 @@ char* atmodem_exec(struct modem* modem)
 								val = 0;
 								break;
 						}
-						sprintf(respbuf, "%c%03lu%c%c%s", modem->lf, val, modem->cr, modem->lf, ok(modem));
+						safe_snprintf(respbuf, sizeof(respbuf), "%c%03lu%c%c%s"
+							,modem->lf, val, modem->cr, modem->lf, ok(modem));
 						return respbuf;
 					} else
 						return error(modem);
@@ -928,7 +936,7 @@ BOOL vdd_write(HANDLE* slot, uint8_t* buf, size_t buflen)
 {
 	if(*slot == INVALID_HANDLE_VALUE) {
 		char path[MAX_PATH + 1];
-		sprintf(path, "\\\\.\\mailslot\\sbbsexec\\wr%d", cfg.node_num);
+		SAFEPRINTF(path, "\\\\.\\mailslot\\sbbsexec\\wr%d", cfg.node_num);
 		*slot = CreateFile(path
 			,GENERIC_WRITE
 			,FILE_SHARE_READ
@@ -1000,6 +1008,9 @@ bool read_ini(const char* ini_fname)
 	const char* p = iniGetString(ini, ROOT_SECTION, "BusyNotice", NULL, value);
 	if(p != NULL)
 		SAFECOPY(cfg.busy_notice, p);
+	p = iniGetString(ini, ROOT_SECTION, "AnswerBanner", NULL, value);
+	if(p != NULL)
+		SAFECOPY(cfg.answer_banner, p);
 	return true;
 }
 
@@ -1008,7 +1019,7 @@ int main(int argc, char** argv)
 	int argn = 1;
 	char tmp[256];
 	char path[MAX_PATH + 1];
-	char fullmodemline[MAX_PATH + 1];
+	char fullcmdline[MAX_PATH + 1];
 	uint8_t buf[XTRN_IO_BUF_LEN];
 	uint8_t telnet_buf[sizeof(buf) * 2];
 	size_t rx_buflen = sizeof(buf);
@@ -1025,10 +1036,12 @@ int main(int argc, char** argv)
 	}
 
 	// Default configuration values
+	mode = TELNET;
 	cfg.server_echo = TRUE;
 	cfg.port = IPPORT_TELNET;
-	cfg.address_family = ADDRESS_FAMILY_INET;
+	cfg.address_family = ADDRESS_FAMILY_UNSPEC;
 	SAFECOPY(cfg.busy_notice, "\r\nSorry, not available right now\r\n");
+	SAFEPRINTF(cfg.answer_banner, "\r\n" TITLE " v" VERSION " Copyright %s Rob Swindell\r\n", &__DATE__[7]);
 
 	ini = strListInit();
 	GetModuleFileName(NULL, ini_fname, sizeof(ini_fname) - 1);
@@ -1045,11 +1058,11 @@ int main(int argc, char** argv)
 			break;
 		while(*arg == '-')
 			arg++;
-		if(strcmp(arg, "telnet") == 0) {
+		if(stricmp(arg, "telnet") == 0) {
 			mode = TELNET;
 			continue;
 		}
-		if(strcmp(arg, "raw") == 0) {
+		if(stricmp(arg, "raw") == 0) {
 			mode = RAW;
 			continue;
 		}
@@ -1064,13 +1077,16 @@ int main(int argc, char** argv)
 				cfg.listen = true;
 				arg++;
 				if(*arg != '\0') {
-					listening_interface.addr.sa_family = address_family();
+					listening_interface.addr.sa_family = listen_address_family();
 					if(inet_ptoaddr(arg, &listening_interface, sizeof(listening_interface)) == NULL) {
 						fprintf(stderr, "!Error parsing network address: %s", arg);
 						return EXIT_FAILURE;
 					}
 				}
 				break;
+			case 'n':
+				cfg.node_num = atoi(arg + 1);
+				break;
 			case 'p':
 				cfg.port = atoi(arg + 1);
 				break;
@@ -1092,9 +1108,19 @@ int main(int argc, char** argv)
 				break;
 			case 'B':
 				rx_buflen = min(strtoul(arg + 1, NULL, 10), sizeof(buf));
+				break;
 			case 'R':
 				rx_delay = strtoul(arg + 1, NULL, 10);
 				break;
+			case 'I':
+				sbbsexec_mode |= SBBSEXEC_MODE_DOS_IN;
+				break;
+			case 'O':
+				sbbsexec_mode |= SBBSEXEC_MODE_DOS_OUT;
+				break;
+			case 'M':
+				sbbsexec_mode = strtoul(arg + 1, NULL, 0);
+				break;
 			case 'V':
 				fprintf(stdout, "%s/%s\n", GIT_BRANCH, GIT_HASH);
 				return EXIT_SUCCESS;
@@ -1114,13 +1140,13 @@ int main(int argc, char** argv)
 		if(sock != INVALID_SOCKET)
 			listening_sock = sock;
 		else {
-			listening_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
+			listening_sock = socket(listen_address_family(), SOCK_STREAM, IPPROTO_IP);
 			if(listening_sock == INVALID_SOCKET) {
 				fprintf(stderr, "Error %ld creating socket\n", WSAGetLastError());
 				return EXIT_FAILURE;
 			}
 		}
-		listening_interface.addr.sa_family = address_family();
+		listening_interface.addr.sa_family = listen_address_family();
 		inet_setaddrport(&listening_interface, cfg.port);
 		result = bind(listening_sock, &listening_interface.addr, xp_sockaddr_len(&listening_interface));
 		if(result != 0) {
@@ -1156,7 +1182,7 @@ int main(int argc, char** argv)
 	fclose(fp);
 
 	while(1) {
-		sprintf(path, "\\\\.\\mailslot\\sbbsexec\\rd%d", cfg.node_num);
+		SAFEPRINTF(path, "\\\\.\\mailslot\\sbbsexec\\rd%d", cfg.node_num);
 		rdslot = CreateMailslot(path
 			,sizeof(buf)/2			// Maximum message size (0=unlimited)
 			,0						// Read time-out
@@ -1170,7 +1196,7 @@ int main(int argc, char** argv)
 		++cfg.node_num;
 	}
 
-	sprintf(path, "sbbsexec_carrier%d", cfg.node_num);
+	SAFEPRINTF(path, "sbbsexec_carrier%d", cfg.node_num);
 	carrier_event = CreateEvent(
 		 NULL	// pointer to security attributes
 		,FALSE	// flag for manual-reset event
@@ -1182,7 +1208,7 @@ int main(int argc, char** argv)
 		return EXIT_FAILURE;
 	}
 
-	sprintf(path, "sbbsexec_hangup%d", cfg.node_num);
+	SAFEPRINTF(path, "sbbsexec_hangup%d", cfg.node_num);
 	hangup_event = CreateEvent(
 		 NULL	// pointer to security attributes
 		,FALSE	// flag for manual-reset event
@@ -1194,7 +1220,7 @@ int main(int argc, char** argv)
 		return EXIT_FAILURE;
 	}
 
-	sprintf(path, "sbbsexec_hungup%d", cfg.node_num);
+	SAFEPRINTF(path, "sbbsexec_hungup%d", cfg.node_num);
 	hungup_event = CreateEvent(
 		 NULL	// pointer to security attributes
 		,TRUE	// flag for manual-reset event
@@ -1211,12 +1237,13 @@ int main(int argc, char** argv)
 
 	BOOL x64 = FALSE;
 	IsWow64Process(GetCurrentProcess(), &x64);
-	sprintf(fullmodemline, "dosxtrn.exe %s %s %u %s", dropfile, x64 ? "x64" : "NT", cfg.node_num, ini_fname);
+	safe_snprintf(fullcmdline, sizeof(fullcmdline), "dosxtrn.exe %s %s %u %u %s"
+		,dropfile, x64 ? "x64" : "NT", cfg.node_num, sbbsexec_mode, ini_fname);
 
 	PROCESS_INFORMATION process_info;
     if(!CreateProcess(
 		NULL,			// pointer to name of executable module
-		fullmodemline,  	// pointer to command line string
+		fullcmdline,  	// pointer to command line string
 		NULL,  			// process security attributes
 		NULL,   		// thread security attributes
 		FALSE, 			// handle inheritance flag
@@ -1226,10 +1253,10 @@ int main(int argc, char** argv)
 		&startup_info,  // pointer to STARTUPINFO
 		&process_info  	// pointer to PROCESS_INFORMATION
 		)) {
-        fprintf(stderr, "Error %ld executing '%s'", GetLastError(), fullmodemline);
+        fprintf(stderr, "Error %ld executing '%s'", GetLastError(), fullcmdline);
 		return EXIT_FAILURE;
 	}
-	printf("Executed '%s' successfully\n", fullmodemline);
+	printf("Executed '%s' successfully\n", fullcmdline);
 
 	CloseHandle(process_info.hThread);
 
@@ -1322,6 +1349,7 @@ int main(int argc, char** argv)
 		if(rd) {
 			if(modem.online) {
 				if(modem.esc_count) {
+					dprintf("Esc count = %d", modem.esc_count);
 					if(modem.esc_count >= 3)
 						modem.esc_count = 0;
 					else  {
@@ -1332,8 +1360,10 @@ int main(int argc, char** argv)
 								modem.esc_count = 0;
 					}
 				} else {
-					if(now - lasttx > guard_time(&modem))
+					if(now - lasttx > guard_time(&modem)) {
 						modem.esc_count = count_esc(&modem, buf, rd);
+						dprintf("New esc count = %d", modem.esc_count);
+					}
 				}
 				size_t len = rd;
 				uint8_t* p = buf;