diff --git a/src/sbbs3/execvxd.h b/src/sbbs3/execvxd.h
index 7ffb8abbcd39a5421935b65bd02eca1b33be01a5..3007c2bc42861c61922d10b4f5d1f22ca1c73642 100644
--- a/src/sbbs3/execvxd.h
+++ b/src/sbbs3/execvxd.h
@@ -47,6 +47,7 @@
 #define SBBSEXEC_MODE_FOSSIL		(0)
 #define SBBSEXEC_MODE_DOS_IN		(1<<0)
 #define SBBSEXEC_MODE_DOS_OUT		(1<<1)
+#define SBBSEXEC_MODE_UART			(1<<2)
 
 enum {
 	 SBBSEXEC_ERROR_INUSE=1
diff --git a/src/sbbs3/sbbsdefs.h b/src/sbbs3/sbbsdefs.h
index 3ce43681b40ffe88fb57e193431452b46597aaa3..4879fe1fdd732deb12938b8bfac2b92cc43cc6dd 100644
--- a/src/sbbs3/sbbsdefs.h
+++ b/src/sbbs3/sbbsdefs.h
@@ -395,6 +395,7 @@ typedef enum {						/* Values for xtrn_t.event				*/
 #define SAVECOLUMNS		(1<<22)		/* Save/share current terminal width	*/
 #define XTRN_UTF8		(1<<23)		/* External program supports UTF-8		*/
 #define XTRN_TEMP_DIR	(1<<24)		/* Place drop files in temp dir			*/
+#define XTRN_UART		(1<<25)		/* Disable the int14h/FOSSIL driver		*/
 #define XTRN_CONIO		(1<<31)		/* Intercept Windows Console I/O (Drwy)	*/
 
 									/* Bits in cfg.xtrn_misc				*/
@@ -810,6 +811,7 @@ enum {							/* readmail and delmailidx which types		*/
 #define EX_CHKTIME	XTRN_CHKTIME	/* Check time left						*/
 #define EX_NOECHO	XTRN_NOECHO		/* Don't echo stdin to stdout 			*/
 #define EX_STDIO	(EX_STDIN|EX_STDOUT)
+#define EX_UART		XTRN_UART
 #define EX_NOLOG	(1<<30)		/* Don't log intercepted stdio				*/
 #define EX_CONIO	(1<<31)		/* Intercept Windows console I/O (doorway)	*/
 #define EX_UNSPECIFIED	-1
diff --git a/src/sbbs3/scfg/scfg.h b/src/sbbs3/scfg/scfg.h
index bfbd9d0dd3338e2a3fb43f4ee2e466e5aa942d91..032e154cbb723d1575b894b29a8e80b2395caa9f 100644
--- a/src/sbbs3/scfg/scfg.h
+++ b/src/sbbs3/scfg/scfg.h
@@ -153,6 +153,8 @@ void sort_subs(int grpnum);
 void sort_dirs(int libnum);
 unsigned subs_in_group(unsigned grpnum);
 char random_code_char(void);
+const char* io_method(uint32_t mode);
+void choose_io_method(uint32_t* misc);
 BOOL load_main_cfg(scfg_t*, char*, size_t);
 BOOL load_node_cfg(scfg_t*, char*, size_t);
 BOOL load_msgs_cfg(scfg_t*, char*, size_t);
diff --git a/src/sbbs3/scfg/scfgchat.c b/src/sbbs3/scfg/scfgchat.c
index 3b50754d588ad15793cdfe57c51cb1042cc9055e..902ca354110a1e5f6409732b6997bc1ebdd42105 100644
--- a/src/sbbs3/scfg/scfgchat.c
+++ b/src/sbbs3/scfg/scfgchat.c
@@ -114,9 +114,7 @@ void page_cfg()
 			k=0;
 			sprintf(opt[k++],"%-27.27s%s","Command Line",cfg.page[i]->cmd);
 			sprintf(opt[k++],"%-27.27s%s","Access Requirements",cfg.page[i]->arstr);
-			sprintf(opt[k++],"%-27.27s%s","Intercept I/O"
-				,(cfg.page[i]->misc&XTRN_STDIO) ? "Standard"
-					:cfg.page[i]->misc&XTRN_CONIO ? "Console":"No");
+			sprintf(opt[k++],"%-27.27s%s","I/O Method", io_method(cfg.page[i]->misc));
 			sprintf(opt[k++],"%-27.27s%s","Native Executable"
 				,cfg.page[i]->misc&XTRN_NATIVE ? "Yes" : "No");
 			sprintf(opt[k++],"%-27.27s%s","Use Shell to Execute"
@@ -144,49 +142,7 @@ void page_cfg()
 					getar(str,cfg.page[i]->arstr);
 					break;
 				case 2:
-					switch(cfg.page[i]->misc&(XTRN_STDIO|XTRN_CONIO)) {
-						case XTRN_STDIO:
-							k=0;
-							break;
-						case XTRN_CONIO:
-							k=1;
-							break;
-						default:
-							k=2;
-					}
-					strcpy(opt[0],"Standard");
-					strcpy(opt[1],"Console");
-					strcpy(opt[2],"No");
-					opt[3][0]=0;
-					uifc.helpbuf=
-						"`Intercept I/O:`\n"
-						"\n"
-						"If you wish the screen output and keyboard input to be intercepted\n"
-						"when running this chat pager, set this option to either `Standard` or ~Console~.\n"
-					;
-					switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0,"Intercept I/O"
-						,opt)) {
-					case 0:
-						if((cfg.page[i]->misc&(XTRN_STDIO|XTRN_CONIO)) != XTRN_STDIO) {
-							cfg.page[i]->misc|=XTRN_STDIO;
-							cfg.page[i]->misc&=~XTRN_CONIO;
-							uifc.changes=1; 
-						}
-						break;
-					case 1:
-						if((cfg.page[i]->misc&(XTRN_STDIO|XTRN_CONIO)) != XTRN_CONIO) {
-							cfg.page[i]->misc|=XTRN_CONIO;
-							cfg.page[i]->misc&=~XTRN_STDIO;
-							uifc.changes=1; 
-						}
-						break;
-					case 2:
-						if((cfg.page[i]->misc&(XTRN_STDIO|XTRN_CONIO)) != 0) {
-							cfg.page[i]->misc&=~(XTRN_STDIO|XTRN_CONIO);
-							uifc.changes=1; 
-						}
-						break;
-					}
+					choose_io_method(&cfg.page[i]->misc);
 					break;
 				case 3:
 					k=(cfg.page[i]->misc&XTRN_NATIVE) ? 0:1;
diff --git a/src/sbbs3/scfg/scfgxtrn.c b/src/sbbs3/scfg/scfgxtrn.c
index d6e2d6cef002c66d2304a2cad75bc76e27f68f35..a26b90f183ef1dc9326e5097cbaedb07b265715d 100644
--- a/src/sbbs3/scfg/scfgxtrn.c
+++ b/src/sbbs3/scfg/scfgxtrn.c
@@ -875,6 +875,145 @@ void tevents_cfg()
 	}
 }
 
+const char* io_method(uint32_t mode)
+{
+	static char str[128];
+
+	sprintf(str,"%s%s%s"
+		,mode & XTRN_UART ? "UART"
+			: (mode & XTRN_STDIO ? "Standard"
+				: mode & XTRN_CONIO ? "Console": (mode & XTRN_NATIVE ? "Socket" : "FOSSIL or UART"))
+		,(mode & (XTRN_STDIO|WWIVCOLOR)) == (XTRN_STDIO|WWIVCOLOR) ? ", WWIV Color" : ""
+		,(mode & (XTRN_STDIO|XTRN_NOECHO)) == (XTRN_STDIO|XTRN_NOECHO) ? ", No Echo" : "");
+	return str;
+}
+
+void choose_io_method(uint32_t* misc)
+{
+	int k;
+
+	switch((*misc) & (XTRN_STDIO|XTRN_UART)) {
+		case XTRN_STDIO:
+			k=0;
+			break;
+		case XTRN_UART:
+			k=2;
+			break;
+		default:
+			k=1;
+			break;
+	}
+	strcpy(opt[0], "Standard");
+	if((*misc) & XTRN_NATIVE) {
+		uifc.helpbuf=
+			"`I/O Method:`\n"
+			"\n"
+			"Select the type of input and output to/from this program that you would\n"
+			"like to have intercepted and directed to the remote user's terminal.\n"
+			"\n"
+			"`Standard`\n"
+			"   So-called 'Standard I/O' of console mode (typically UNIX) programs.\n"
+			"\n"
+			"`Socket`\n"
+			"   Stream (TCP) socket interface to a native (e.g. Win32 or *nix)\n"
+			"   program. The socket descriptor/handle (number) is passed to the\n"
+			"   program either via drop file (e.g. DOOR32.SYS) or command-line\n"
+			"   option.\n"
+			"\n"
+			"~ Note ~\n"
+			"   This setting is not applied when invoking Baja or JavaScript modules.\n"
+		;
+		strcpy(opt[1], "Socket");
+		opt[2][0] = '\0';
+	} else {
+		uifc.helpbuf=
+			"`I/O Method:`\n"
+			"\n"
+			"Select the type of input and output to/from this program that you would\n"
+			"like to have intercepted and directed to the remote user's terminal.\n"
+			"\n"
+			"`Standard`\n"
+			"   So-called 'Standard I/O' of console mode (typically UNIX) programs.\n"
+			"   Int29h is intercepted for output and int16h for keyboard input.\n"
+			"   Will not intercept direct screen writes or PC-BIOS int10h calls.\n"
+			"\n"
+			"`FOSSIL`\n"
+			"   Int14h (PC-BIOS) serial communication interface to 16-bit\n"
+			"   MS-DOS programs. Most traditional BBS door games will support FOSSIL.\n"
+			"   The port number (contained in the DX register of int14h calls) is\n"
+			"   ignored by the Synchronet FOSSIL driver.\n"
+			"\n"
+			"`UART`\n"
+			"   Communication port I/O of 16-bit MS-DOS programs via emulation of an\n"
+			"   NS8250 Universal Asynchronous Receiver/Transmitter (UART), by\n"
+			"   default as an IBM-PC `COM1` port (I/O port 3F8h, IRQ 4).\n"
+			"\n"
+			"~ Note ~\n"
+			"   This setting is not applied when invoking Baja or JavaScript modules.\n"
+		;
+		strcpy(opt[1], "FOSSIL or UART");
+		strcpy(opt[2], "UART");
+		opt[3][0] = '\0';
+	}
+	switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0,"I/O Method"
+		,opt)) {
+		case 0: /* Standard I/O */
+			if(((*misc) & (XTRN_STDIO|XTRN_UART)) != XTRN_STDIO) {
+				(*misc) |=XTRN_STDIO;
+				(*misc) &=~XTRN_UART;
+				uifc.changes = TRUE;
+			}
+			k=((*misc) & WWIVCOLOR) ? 0:1;
+			uifc.helpbuf=
+				"`Program Uses WWIV Color Codes:`\n"
+				"\n"
+				"If this program was written for use exclusively under ~WWIV~ BBS\n"
+				"software, set this option to ~Yes~.\n"
+			;
+			k=uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
+				,"Program Uses WWIV Color Codes"
+				,uifcYesNoOpts);
+			if(!k && !((*misc) & WWIVCOLOR)) {
+				(*misc) |= WWIVCOLOR;
+				uifc.changes=TRUE; 
+			}
+			else if(k==1 && ((*misc)&WWIVCOLOR)) {
+				(*misc) &= ~WWIVCOLOR;
+				uifc.changes=TRUE; 
+			}
+			k=((*misc) & XTRN_NOECHO) ? 1:0;
+			uifc.helpbuf=
+				"`Echo Input:`\n"
+				"\n"
+				"If you want the BBS to copy (\"echo\") all keyboard input to the screen\n"
+				"output, set this option to ~Yes~ (for native Win32 programs only).\n"
+			;
+			k=uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
+				,"Echo Keyboard Input"
+				,uifcYesNoOpts);
+			if(!k && ((*misc) & XTRN_NOECHO)) {
+				(*misc) &=~XTRN_NOECHO;
+				uifc.changes=TRUE; 
+			} else if(k==1 && !((*misc) & XTRN_NOECHO)) {
+				(*misc) |= XTRN_NOECHO;
+				uifc.changes=TRUE; 
+			}
+			break;
+		case 1:	/* FOSSIL or Socket */
+			if(((*misc) & (XTRN_STDIO|XTRN_UART)) != 0) {
+				(*misc) &= ~(XTRN_UART|XTRN_STDIO|WWIVCOLOR|XTRN_NOECHO);
+				uifc.changes=TRUE; 
+			}
+			break;
+		case 2: /* UART */
+			if(((*misc) & (XTRN_STDIO|XTRN_UART)) != XTRN_UART) {
+				(*misc) |= XTRN_UART;
+				(*misc) &= ~(XTRN_STDIO|WWIVCOLOR|XTRN_NOECHO);
+				uifc.changes=TRUE; 
+			}
+			break;
+	}
+}
 
 void xtrn_cfg(uint section)
 {
@@ -997,13 +1136,7 @@ void xtrn_cfg(uint section)
 				,cfg.xtrn[i]->run_arstr);
 			sprintf(opt[k++],"%-27.27s%s","Multiple Concurrent Users"
 				,cfg.xtrn[i]->misc&MULTIUSER ? "Yes" : "No");
-			sprintf(opt[k++],"%-27.27s%s%s%s","Intercept I/O"
-				,cfg.xtrn[i]->misc&XTRN_STDIO ? "Standard"
-					: cfg.xtrn[i]->misc&XTRN_CONIO ? "Console":"No"
-				,(cfg.xtrn[i]->misc&(XTRN_STDIO|WWIVCOLOR))
-					==(XTRN_STDIO|WWIVCOLOR) ? ", WWIV Color" : nulstr
-				,(cfg.xtrn[i]->misc&(XTRN_STDIO|XTRN_NOECHO))
-					==(XTRN_STDIO|XTRN_NOECHO) ? ", No Echo" : nulstr);
+			sprintf(opt[k++],"%-27.27s%s","I/O Method", io_method(cfg.xtrn[i]->misc));
 			sprintf(opt[k++],"%-27.27s%s","Native Executable/Script"
 				,cfg.xtrn[i]->misc&XTRN_NATIVE ? "Yes" : "No");
 			sprintf(opt[k++],"%-27.27s%s",use_shell_opt
@@ -1171,84 +1304,7 @@ void xtrn_cfg(uint section)
 					}
 					break;
 				case 9:
-					switch(cfg.xtrn[i]->misc&(XTRN_STDIO|XTRN_CONIO)) {
-						case XTRN_STDIO:
-							k=0;
-							break;
-						case XTRN_CONIO:
-							k=1;
-							break;
-						default:
-							k=2;
-					}
-					strcpy(opt[0],"Standard");
-					strcpy(opt[1],"Console");
-					strcpy(opt[2],"No");
-					opt[3][0]=0;
-					uifc.helpbuf=
-						"`Intercept I/O:`\n"
-						"\n"
-						"If this online program uses a FOSSIL driver or SOCKET communications,\n"
-						"set this option to `No`.\n"
-					;
-					switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0,"Intercept I/O"
-						,opt)) {
-						case 0: /* Standard I/O */
-							if((cfg.xtrn[i]->misc&(XTRN_STDIO|XTRN_CONIO)) != XTRN_STDIO) {
-								cfg.xtrn[i]->misc|=XTRN_STDIO;
-								cfg.xtrn[i]->misc&=~XTRN_CONIO;
-								uifc.changes=1;
-							}
-							k=(cfg.xtrn[i]->misc&WWIVCOLOR) ? 0:1;
-							uifc.helpbuf=
-								"`Program Uses WWIV Color Codes:`\n"
-								"\n"
-								"If this program was written for use exclusively under ~WWIV~ BBS\n"
-								"software, set this option to ~Yes~.\n"
-							;
-							k=uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
-								,"Program Uses WWIV Color Codes"
-								,uifcYesNoOpts);
-							if(!k && !(cfg.xtrn[i]->misc&WWIVCOLOR)) {
-								cfg.xtrn[i]->misc|=WWIVCOLOR;
-								uifc.changes=TRUE; 
-							}
-							else if(k==1 && (cfg.xtrn[i]->misc&WWIVCOLOR)) {
-								cfg.xtrn[i]->misc&=~WWIVCOLOR;
-								uifc.changes=TRUE; 
-							}
-							k=(cfg.xtrn[i]->misc&XTRN_NOECHO) ? 1:0;
-							uifc.helpbuf=
-								"`Echo Input:`\n"
-								"\n"
-								"If you want the BBS to copy (\"echo\") all keyboard input to the screen\n"
-								"output, set this option to ~Yes~ (for native Win32 programs only).\n"
-							;
-							k=uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
-								,"Echo Keyboard Input"
-								,uifcYesNoOpts);
-							if(!k && (cfg.xtrn[i]->misc&XTRN_NOECHO)) {
-								cfg.xtrn[i]->misc&=~XTRN_NOECHO;
-								uifc.changes=TRUE; 
-							} else if(k==1 && !(cfg.xtrn[i]->misc&XTRN_NOECHO)) {
-								cfg.xtrn[i]->misc|=XTRN_NOECHO;
-								uifc.changes=TRUE; 
-							}
-							break;
-						case 1: /* Console I/O */
-							if((cfg.xtrn[i]->misc&(XTRN_STDIO|XTRN_CONIO)) != XTRN_CONIO) {
-								cfg.xtrn[i]->misc|=XTRN_CONIO;
-								cfg.xtrn[i]->misc&=~(XTRN_STDIO|WWIVCOLOR|XTRN_NOECHO);
-								uifc.changes=TRUE; 
-							}
-							break;
-						case 2:	/* No */
-							if((cfg.xtrn[i]->misc&(XTRN_STDIO|XTRN_CONIO)) != 0) {
-								cfg.xtrn[i]->misc&=~(XTRN_CONIO|XTRN_STDIO|WWIVCOLOR|XTRN_NOECHO);
-								uifc.changes=TRUE; 
-							}
-							break;
-					}
+					choose_io_method(&cfg.xtrn[i]->misc);
 					break;
 				case 10:
 					k=(cfg.xtrn[i]->misc&XTRN_NATIVE) ? 0:1;
@@ -1673,11 +1729,7 @@ void xedit_cfg()
 			sprintf(opt[k++],"%-32.32s%s","Internal Code",cfg.xedit[i]->code);
 			sprintf(opt[k++],"%-32.32s%s","Command Line",cfg.xedit[i]->rcmd);
 			sprintf(opt[k++],"%-32.32s%s","Access Requirements",cfg.xedit[i]->arstr);
-			sprintf(opt[k++],"%-32.32s%s%s","Intercept I/O"
-				,cfg.xedit[i]->misc&XTRN_STDIO ? "Standard"
-					:cfg.xedit[i]->misc&XTRN_CONIO ? "Console":"No"
-				,(cfg.xedit[i]->misc&(XTRN_STDIO|WWIVCOLOR))
-					==(XTRN_STDIO|WWIVCOLOR) ? ", WWIV Color" : nulstr);
+			sprintf(opt[k++],"%-32.32s%s","I/O Method", io_method(cfg.xedit[i]->misc));
 			sprintf(opt[k++],"%-32.32s%s","Native Executable/Script"
 				,cfg.xedit[i]->misc&XTRN_NATIVE ? "Yes" : "No");
 			sprintf(opt[k++],"%-32.32s%s",use_shell_opt
@@ -1788,66 +1840,7 @@ void xedit_cfg()
 					getar(str,cfg.xedit[i]->arstr);
 					break;
 				case 4:
-					switch(cfg.xedit[i]->misc&(XTRN_STDIO|XTRN_CONIO)) {
-						case XTRN_STDIO:
-							k=0;
-							break;
-						case XTRN_CONIO:
-							k=1;
-							break;
-						default:
-							k=2;
-							break;
-					}
-					strcpy(opt[0],"Standard");
-					strcpy(opt[1],"Console");
-					strcpy(opt[2],"No");
-					opt[3][0]=0;
-					uifc.helpbuf=
-						"`Intercept I/O:`\n"
-						"\n"
-						"If this program uses FOSSIL, Socket, or UART communications,\n"
-						"set this option to `No`.\n"
-					;
-					switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0,"Intercept I/O"	,opt)) {
-						case 0: /* Standard */
-							if((cfg.xedit[i]->misc&(XTRN_STDIO|XTRN_CONIO)) != XTRN_STDIO) {
-								cfg.xedit[i]->misc|=XTRN_STDIO;
-								cfg.xedit[i]->misc&=~XTRN_CONIO;
-								uifc.changes=TRUE; 
-							}
-							k=(cfg.xedit[i]->misc&WWIVCOLOR) ? 0:1;
-							uifc.helpbuf=
-								".Editor Uses WWIV Color Codes:.\n"
-								"\n"
-								"If this editor was written for use exclusively under WWIV, set this\n"
-								"option to .Yes..\n"
-							;
-							k=uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
-								,"Editor Uses WWIV Color Codes",uifcYesNoOpts);
-							if(!k && !(cfg.xedit[i]->misc&WWIVCOLOR)) {
-								cfg.xedit[i]->misc|=WWIVCOLOR;
-								uifc.changes=TRUE; 
-							}
-							else if(k==1 && (cfg.xedit[i]->misc&WWIVCOLOR)) {
-								cfg.xedit[i]->misc&=~WWIVCOLOR;
-								uifc.changes=TRUE; 
-							}
-							break;
-						case 1: /* Console */
-							if((cfg.xedit[i]->misc&(XTRN_STDIO|XTRN_CONIO)) != XTRN_CONIO) {
-								cfg.xedit[i]->misc|=XTRN_CONIO;
-								cfg.xedit[i]->misc&=~(XTRN_STDIO|WWIVCOLOR);
-								uifc.changes=TRUE; 
-							}
-							break;
-						case 2: /* No */
-							if((cfg.xedit[i]->misc&(XTRN_STDIO|XTRN_CONIO)) != 0) {
-								cfg.xedit[i]->misc&=~(XTRN_CONIO|XTRN_STDIO|WWIVCOLOR);
-								uifc.changes=TRUE; 
-							}
-							break;
-					}
+					choose_io_method(&cfg.xedit[i]->misc);
 					break;
 				case 5:
 					k=(cfg.xedit[i]->misc&XTRN_NATIVE) ? 0:1;
diff --git a/src/sbbs3/xtrn.cpp b/src/sbbs3/xtrn.cpp
index 49e8762df2a8d823f3a44348f84124e2cc76a8ff..ae7deb7e61a65125eb6478c71430c06cd375afab 100644
--- a/src/sbbs3/xtrn.cpp
+++ b/src/sbbs3/xtrn.cpp
@@ -478,11 +478,15 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
         SAFEPRINTF2(fullcmdline, "%sDOSXTRN.EXE %s", cfg.exec_dir, path);
 
 		if(!(mode&EX_OFFLINE)) {
-			i=SBBSEXEC_MODE_FOSSIL;
-			if(mode&EX_STDIN)
-           		i|=SBBSEXEC_MODE_DOS_IN;
-			if(mode&EX_STDOUT)
-        		i|=SBBSEXEC_MODE_DOS_OUT;
+			if(mode & EX_UART)
+				i=SBBSEXEC_MODE_UART;
+			else {
+				i=SBBSEXEC_MODE_FOSSIL;
+				if(mode&EX_STDIN)
+           			i|=SBBSEXEC_MODE_DOS_IN;
+				if(mode&EX_STDOUT)
+        			i|=SBBSEXEC_MODE_DOS_OUT;
+			}
 			sprintf(str," NT %u %u"
 				,cfg.node_num,i);
 			strcat(fullcmdline,str);