diff --git a/ctrl/sbbs.ini b/ctrl/sbbs.ini
index df19c8ae081249c6874e9fcbb35d2aecbb782619..c47ddf1caa6523704bc736eff165a2f961706e60 100644
--- a/ctrl/sbbs.ini
+++ b/ctrl/sbbs.ini
@@ -77,7 +77,9 @@
 	Pet40Port = 64
 	; TCP port for 80-column PETSCII connections (any terminal protocol):
 	Pet80Port = 128
-	; Note on PETSCII support: you must add the same port(s) to one of your
+	; TCP port for 40-column MODE7 connections (any termnial protocol):
+	Mode7Port = 5050
+	; Note on PETSCII and MODE7 support: you must add the same port(s) to one of your
 	; *Interface= values above to open/listen/accept connections on that port.
 	; Example:
 	;   TelnetInterface = 71.95.196.34,71.95.196.34:64,71.95.196.34:128
diff --git a/ctrl/text.dat b/ctrl/text.dat
index 7a9f5d4c73b35d2529a82efc64c917d060f24775..424225c7e11980a201e1cd4209991dd20db21cb0 100644
--- a/ctrl/text.dat
+++ b/ctrl/text.dat
@@ -1124,3 +1124,5 @@
 " %c \1g%.10s\1n %c %.127s%c"							   935 QWKTagLineFmt
 "\1n\r\n\1b\1hQWK Control [\1c%s\1b]: \1g%s\r\n"		   936 QWKControlCommand
 "Unrecognized Control Command!\1n\r\n"					   937 QWKBadControlCommand
+"Mode 7 terminal detected"								   938 Mode7TerminalDetected
+"Are you using a Mode 7 terminal"						   939 Mode7TerminalQ
diff --git a/exec/load/termdesc.js b/exec/load/termdesc.js
index c514c06524dd40f5a614c49078be3d9ab611f667..ed0135707a4d2ef495b4badd356b324a15e40be8 100644
--- a/exec/load/termdesc.js
+++ b/exec/load/termdesc.js
@@ -22,6 +22,8 @@ function charset(term)
 		term = console.term_supports();
 	if(term & USER_PETSCII)
 		return "CBM-ASCII";
+	if(term & USER_MODE7)
+		return "MODE7";
 	if(term & USER_UTF8)
 		return "UTF-8";
 	if(term & USER_NO_EXASCII)
@@ -62,6 +64,8 @@ function type(verbose, usr)
 	var type = "DUMB";
 	if(term & USER_PETSCII)
 		type = "PETSCII";
+	if(term & USER_MODE7)
+		type = "MODE7";
 	if(term & USER_RIP)
 		type = "RIP";
 	if(term & USER_ANSI)
@@ -72,6 +76,8 @@ function type(verbose, usr)
 	// Verbose
 	if(term & USER_PETSCII)
 		return ((usr.settings & USER_AUTOTERM) ? bbs.text(TerminalAutoDetect) : "") + "CBM/PETSCII";
+	if(term & USER_MODE7)
+		return ((usr.settings & USER_AUTOTERM) ? bbs.text(TerminalAutoDetect) : "") + "MODE7";
 	return format("%s%s / %s %s%s%s"
 		,(usr.settings & USER_AUTOTERM) ? bbs.text(TerminalAutoDetect) : ""
 		,this.charset(term)
diff --git a/exec/load/text.js b/exec/load/text.js
index ab3fc80346f3939ade57bb921114da7eff2a9421..a780a764743648cb90270f73f57acb9b1ad72077 100644
--- a/exec/load/text.js
+++ b/exec/load/text.js
@@ -944,7 +944,9 @@ var QWKEndOfMessage=934;
 var QWKTagLineFmt=935;
 var QWKControlCommand=936;
 var QWKBadControlCommand=937;
+var Mode7TerminalDetected=938;
+var Mode7TerminalQ=939;
 
-var TOTAL_TEXT=938;
+var TOTAL_TEXT=940;
 
 this;
diff --git a/exec/load/userdefs.js b/exec/load/userdefs.js
index 4f7aad07d75c64bf831dfcd7b6691c72bc4f01f7..d09319efa7b237339e0817f43e1ac8c03bacd2a5 100644
--- a/exec/load/userdefs.js
+++ b/exec/load/userdefs.js
@@ -24,7 +24,7 @@ const USER_AUTOTERM	    = (1<<17);	// Autodetect terminal type
 const USER_COLDKEYS	    = (1<<18);	// No hot-keys								
 const USER_EXTDESC 	    = (1<<19);	// Extended file descriptions				
 const USER_AUTOHANG	    = (1<<20);	// Auto-hang-up after transfer				
-const USER_WIP 		    = (1<<21);	// Supports WIP terminal emulation			
+const USER_MODE7	    = (1<<21);	// BBC Micro Mode 7 terminal support
 const USER_AUTOLOGON    = (1<<22);	// AutoLogon via IP							
 const USER_HTML		    = (1<<23);	// Using Deuce's HTML terminal (*cough*)	
 const USER_NOPAUSESPIN  = (1<<24);	// No spinning cursor at pause prompt		
diff --git a/exec/login.js b/exec/login.js
index a4c7324916f33d8a8406800245ba54a03fdcb7c5..347eb97e9e827ceef7ce6c816685adec43091ba6 100644
--- a/exec/login.js
+++ b/exec/login.js
@@ -27,7 +27,7 @@ if(!bbs.online)
 	exit();
 var inactive_hangup = parseInt(options.inactive_hangup, 10);
 if(inactive_hangup && inactive_hangup < console.max_socket_inactivity
-	&& !(console.autoterm&(USER_ANSI | USER_PETSCII | USER_UTF8))) {
+	&& !(console.autoterm&(USER_ANSI | USER_PETSCII | USER_UTF8 | USER_MODE7))) {
 	console.max_socket_inactivity = inactive_hangup;
 	log(LOG_NOTICE, "terminal not detected, reducing inactivity hang-up timeout to " + console.max_socket_inactivity + " seconds");
 }
diff --git a/exec/logon.js b/exec/logon.js
index 6094ea5ddaf410e9e5c0f022d14356a3c2b3581f..5be63f02994fa98b2ab9719c7121d9b4bb4cecc5 100644
--- a/exec/logon.js
+++ b/exec/logon.js
@@ -11,6 +11,12 @@
 
 require("sbbsdefs.js", 'SS_RLOGIN');
 require("nodedefs.js", 'NODE_QUIET');
+
+if(console.term_supports(USER_MODE7)) {
+	log(LOG_DEBUG, "Setting users language to m7");
+	user.lang = "m7";
+}
+
 if(!bbs.mods.avatar_lib)
 	bbs.mods.avatar_lib = load({}, 'avatar_lib.js');
 if(!bbs.mods.logonlist_lib)
diff --git a/exec/logonlist.js b/exec/logonlist.js
index da7f527347b8b0bb68f0ad7a8bf86c1e58d83f4f..63b174aa0bf3b2b83703160021847124744283e9 100644
--- a/exec/logonlist.js
+++ b/exec/logonlist.js
@@ -45,6 +45,13 @@ if(!js.global.bbs) {
 if(!bbs.mods.logonlist_lib)
 	bbs.mods.logonlist_lib = load({}, 'logonlist_lib.js');
 var options = load("modopts.js", "logonlist");
+function dump_objs(obj) {
+        Object.keys(obj).forEach(function (e) {
+                writeln(e + ': ' + JSON.stringify(obj[e]));
+        });
+}
+dump_objs(options);
+writeln("lang: " + user.lang);
 if(!options)
 	options = {};
 if(options.last_few_callers === undefined)
diff --git a/src/sbbs3/answer.cpp b/src/sbbs3/answer.cpp
index 2c0e2921b3ffc0d37c23498349bd229259306fea..62a45ca9c90d96e09a96b6f98c98f7154eb8c2a1 100644
--- a/src/sbbs3/answer.cpp
+++ b/src/sbbs3/answer.cpp
@@ -553,6 +553,9 @@ bool sbbs_t::answer()
 			SAFECOPY(terminal, "PETSCII");
 			outchar(FF);
 			center(str);
+		} else if (autoterm & MODE7) {
+			SAFECOPY(terminal, "MODE7");
+			center(str);
 		} else {    /* ANSI+ terminal detection */
 			putcom( "\r\n"      /* locate cursor at column 1 */
 			        "\x1b[s"    /* save cursor position (necessary for HyperTerm auto-ANSI) */
diff --git a/src/sbbs3/ars.c b/src/sbbs3/ars.c
index 9f1a995d163580a4b065c21997986bc4e3685beb..2719f0a12b8bc78eaeb92c51c0a093f6a65abfca 100644
--- a/src/sbbs3/ars.c
+++ b/src/sbbs3/ars.c
@@ -337,6 +337,10 @@ uchar* arstr(ushort* count, const char* str, scfg_t* cfg, uchar* ar_buf)
 				artype = AR_PETSCII;
 				i += 6;
 			}
+			else if (!strnicmp(str + i, "MODE7", 5)) {
+				artype = AR_MODE7;
+				i += 4;
+			}
 			else if (!strnicmp(str + i, "ASCII", 5)) {
 				artype = AR_ASCII;
 				i += 4;
diff --git a/src/sbbs3/ars_defs.h b/src/sbbs3/ars_defs.h
index 9d4c003bd56fc9f698e2c0afb553465cc2dbf7ee..fa5de5060506dd44ac5a15925e94555ad985a0bd 100644
--- a/src/sbbs3/ars_defs.h
+++ b/src/sbbs3/ars_defs.h
@@ -116,6 +116,7 @@ enum {                              /* Access requirement binaries */
 	, AR_UTF8
 	, AR_CP437
 	, AR_USERNAME
+	, AR_MODE7
 };
 
 enum ar_type {
@@ -148,6 +149,7 @@ static inline enum ar_type ar_type(int artype)
 		case AR_GUEST:
 		case AR_QNODE:
 		case AR_QUIET:
+		case AR_MODE7:
 			return AR_BOOL;
 		case AR_SUBCODE:
 		case AR_DIRCODE:
diff --git a/src/sbbs3/chk_ar.cpp b/src/sbbs3/chk_ar.cpp
index 731c0796b78d46537d57d721a3d894fb33bf63a1..ca0e4e71895de359263d736c0002b78bc3704bb9 100644
--- a/src/sbbs3/chk_ar.cpp
+++ b/src/sbbs3/chk_ar.cpp
@@ -128,6 +128,20 @@ bool sbbs_t::ar_exp(const uchar **ptrptr, user_t* user, client_t* client)
 					noaccess_val = PETSCII;
 				}
 				break;
+			case AR_MODE7:
+				{
+					int val = term_supports();
+					val &= CHARSET_FLAGS;
+					if (val != CHARSET_MODE7)
+						result = _not;
+					else
+						result = !_not;
+					if (!result) {
+						noaccess_str = text[NoAccessTerminal];
+						noaccess_val = MODE7;
+					}
+				}
+				break;
 			case AR_ASCII:
 				if ((term_supports() & CHARSET_FLAGS) != CHARSET_ASCII)
 					result = _not;
diff --git a/src/sbbs3/con_out.cpp b/src/sbbs3/con_out.cpp
index eda850dfd58735ff572b3578b1b69face90ef4a9..c1b99074afa16b95ce9e8db05e7630ac5d085049 100644
--- a/src/sbbs3/con_out.cpp
+++ b/src/sbbs3/con_out.cpp
@@ -245,6 +245,11 @@ unsigned char cp437_to_petscii(unsigned char ch)
 	return ch;
 }
 
+unsigned char cp437_to_mode7(unsigned char ch)
+{
+	return ch;
+}
+
 /* Perform PETSCII conversion to ANSI-BBS/CP437 */
 int sbbs_t::petscii_to_ansibbs(unsigned char ch)
 {
@@ -539,6 +544,9 @@ char* sbbs_t::term_type(user_t* user, int term, char* str, size_t size)
 	if (term & PETSCII)
 		safe_snprintf(str, size, "%sCBM/PETSCII"
 		              , (user->misc & AUTOTERM) ? text[TerminalAutoDetect] : nulstr);
+	else if (term & MODE7)
+		safe_snprintf(str, size, "%s/MODE7"
+		              , (user->misc & AUTOTERM) ? text[TerminalAutoDetect] : nulstr);
 	else
 		safe_snprintf(str, size, "%s%s / %s %s%s%s"
 		              , (user->misc & AUTOTERM) ? text[TerminalAutoDetect] : nulstr
@@ -560,6 +568,8 @@ const char* sbbs_t::term_type(int term)
 		term = term_supports();
 	if (term & PETSCII)
 		return "PETSCII";
+	if (term & MODE7)
+		return "MODE7";
 	if (term & RIP)
 		return "RIP";
 	if (term & ANSI)
@@ -576,6 +586,8 @@ const char* sbbs_t::term_charset(int term)
 		term = term_supports();
 	if (term & PETSCII)
 		return "CBM-ASCII";
+	if (term & MODE7)
+		return "MODE7";
 	if (term & UTF8)
 		return "UTF-8";
 	if (term & NO_EXASCII)
diff --git a/src/sbbs3/logon.cpp b/src/sbbs3/logon.cpp
index 5c3022c0ca380c9de4a733f1f2ae481bbe579d4c..f9231b09299086e9e9d69e2b3b2eee91f41235c0 100644
--- a/src/sbbs3/logon.cpp
+++ b/src/sbbs3/logon.cpp
@@ -182,8 +182,8 @@ bool sbbs_t::logon()
 	}
 
 	if ((useron.misc & AUTOTERM)
-	    // User manually-enabled PETSCII, but they're logging in with an ANSI (auto-detected) terminal
-	    || ((useron.misc & PETSCII) && (autoterm & ANSI))) {
+	    // User manually-enabled PETSCII or MODE7, but they're logging in with an ANSI (auto-detected) terminal
+	    || (((useron.misc & PETSCII) || (useron.misc & MODE7)) && (autoterm & ANSI))) {
 		useron.misc &= ~(ANSI | RIP | CHARSET_FLAGS);
 		useron.misc |= (AUTOTERM | autoterm);
 	}
diff --git a/src/sbbs3/main.cpp b/src/sbbs3/main.cpp
index 20bea4fad629d17e756a4f979553c6aba448d9f9..2b6feda0e5e27b13f3de3010491ec3b867a7e1c2 100644
--- a/src/sbbs3/main.cpp
+++ b/src/sbbs3/main.cpp
@@ -24,6 +24,7 @@
 #include "telnet.h"
 #include "netwrap.h"
 #include "petdefs.h"
+#include "mode7defs.h"
 #include "filedat.h"
 #include "js_rtpool.h"
 #include "js_request.h"
@@ -5663,6 +5664,12 @@ NO_SSH:
 				sbbs->outcom(PETSCII_UPPERLOWER);
 			}
 
+			if (inet_addrport(&local_addr) == startup->mode7_port) {
+				sbbs->autoterm = MODE7;
+				sbbs->cols = 40;
+				sbbs->rows = 25;
+			}
+
 			sbbs->bprintf("\r\n%s\r\n", VERSION_NOTICE);
 			sbbs->bprintf("%s connection from: %s\r\n", client.protocol, host_ip);
 
diff --git a/src/sbbs3/newuser.cpp b/src/sbbs3/newuser.cpp
index 7775414cbce12091cdd0ec6a671a3907227456c2..e46c3b31bbecabdca9381bb9e8e0b4f0ea6b93c5 100644
--- a/src/sbbs3/newuser.cpp
+++ b/src/sbbs3/newuser.cpp
@@ -153,6 +153,9 @@ bool sbbs_t::newuser()
 			autoterm |= PETSCII;
 			outcom(PETSCII_UPPERLOWER);
 			bputs(text[PetTerminalDetected]);
+		} else if (useron.misc & MODE7) {
+			autoterm |= MODE7;
+			bputs(text[Mode7TerminalDetected]);
 		} else {
 			if (!yesno(text[ExAsciiTerminalQ]))
 				useron.misc |= NO_EXASCII;
diff --git a/src/sbbs3/prntfile.cpp b/src/sbbs3/prntfile.cpp
index caf470b4d592e6bde3d03d8168c089600c02f968..71fc770859255035c1cb83f0a0cd25b5783c3e02 100644
--- a/src/sbbs3/prntfile.cpp
+++ b/src/sbbs3/prntfile.cpp
@@ -22,6 +22,7 @@
 #include "sbbs.h"
 #include "utf8.h"
 #include "petdefs.h"
+#include "mode7defs.h"
 
 #ifndef PRINTFILE_MAX_LINE_LEN
 #define PRINTFILE_MAX_LINE_LEN (8 * 1024)
@@ -54,6 +55,8 @@ bool sbbs_t::printfile(const char* fname, int mode, int org_cols, JSObject* obj)
 			mode |= P_NOPAUSE;
 		} else if (stricmp(p, ".seq") == 0) {
 			mode |= P_PETSCII;
+		} else if (stricmp(p, ".m7") == 0) {
+			mode |= P_MODE7;
 		} else if (stricmp(p, ".utf8") == 0) {
 			mode |= P_UTF8;
 		}
@@ -283,6 +286,8 @@ bool sbbs_t::menu(const char *code, int mode, JSObject* obj)
 				break;
 			if ((term & PETSCII) && menu_exists(code, "seq", path))
 				break;
+			if ((term & MODE7) && menu_exists(code, "m7", path))
+				break;
 			if (term & NO_EXASCII) {
 				next = "asc";
 				last = "msg";
diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h
index 5723daed8b26cf8d187b611ab81eb8725a6efe72..411a1cfe29b9a60b323e2d88d2bdf32fa42247a5 100644
--- a/src/sbbs3/sbbs.h
+++ b/src/sbbs3/sbbs.h
@@ -981,6 +981,7 @@ public:
 	bool	saveline(void);
 	bool	restoreline(void);
 	int		petscii_to_ansibbs(unsigned char);
+	int		mode7_to_ansibbs(unsigned char);
 	size_t	print_utf8_as_cp437(const char*, size_t);
 	int		attr(int);				/* Change text color/attributes */
 	void	ctrl_a(char);			/* Performs Ctrl-Ax attribute changes */
@@ -1431,6 +1432,7 @@ extern "C" {
 
 	/* con_out.cpp */
 	unsigned char		cp437_to_petscii(unsigned char);
+	unsigned char		cp437_to_mode7(unsigned char);
 
 	/* xtrn.cpp */
 	bool				native_executable(scfg_t*, const char* cmdline, int mode);
diff --git a/src/sbbs3/sbbs_ini.c b/src/sbbs3/sbbs_ini.c
index 6ba8123a248e3d6ef0b829f1123d27e8b64ef41e..a550ea306b5dae49a82d0b94f75f0c4d67beb2a9 100644
--- a/src/sbbs3/sbbs_ini.c
+++ b/src/sbbs3/sbbs_ini.c
@@ -448,6 +448,9 @@ void sbbs_read_ini(
 		bbs->pet80_port
 		    = iniGetShortInt(list, section, "Pet80Port", 128);
 
+		bbs->mode7_port
+			= iniGetShortInt(list, section, "Mode7Port", 5050);
+
 		bbs->ssh_port
 		    = iniGetShortInt(list, section, "SSHPort", 22);
 		bbs->ssh_connect_timeout
@@ -936,6 +939,9 @@ bool sbbs_write_ini(
 			if (!iniSetUInt16(lp, section, "Pet80Port", bbs->pet80_port, &style))
 				break;
 
+			if (!iniSetUInt16(lp, section, "Mode7Port", bbs->mode7_port, &style))
+				break;
+
 			if (strListCmp(bbs->ssh_interfaces, global->interfaces) == 0)
 				iniRemoveValue(lp, section, "SSHInterface");
 			else if (!iniSetStringList(lp, section, "SSHInterface", ",", bbs->ssh_interfaces, &style))
diff --git a/src/sbbs3/sbbsdefs.h b/src/sbbs3/sbbsdefs.h
index b4c285ca30ff6749abdf4cfbb99d3d040cae085a..d1ac52f537dd1b404a64e25024b74b548ffe64a1 100644
--- a/src/sbbs3/sbbsdefs.h
+++ b/src/sbbs3/sbbsdefs.h
@@ -568,7 +568,7 @@ typedef enum {                      /* Values for xtrn_t.event				*/
 #define COLDKEYS    (1 << 18)     /* No hot-keys							*/
 #define EXTDESC     (1 << 19)     /* Extended file descriptions			*/
 #define AUTOHANG    (1 << 20)     /* Auto-hang-up after transfer			*/
-#define WIP_UNUSED  (1 << 21)     /* Supports WIP terminal emulation		*/
+#define MODE7		(1 << 21)     /* BBC Micro Mode 7 terminal support	*/
 #define AUTOLOGON   (1 << 22)     /* AutoLogon via IP						*/
 #define HTML_UNUSED (1 << 23)     /* Using Zuul/HTML terminal				*/
 #define NOPAUSESPIN (1 << 24)     /* No spinning cursor at pause prompt	*/
@@ -579,9 +579,10 @@ typedef enum {                      /* Values for xtrn_t.event				*/
 #define MOUSE       (1U << 31)    /* Mouse supported terminal				*/
 
 #define TERM_FLAGS      (ANSI | COLOR | RIP | SWAP_DELETE | ICE_COLOR | MOUSE | CHARSET_FLAGS)
-#define CHARSET_FLAGS   (NO_EXASCII | PETSCII | UTF8)
+#define CHARSET_FLAGS   (NO_EXASCII | PETSCII | UTF8 | MODE7)
 #define CHARSET_ASCII   NO_EXASCII  // US-ASCII
 #define CHARSET_PETSCII PETSCII     // CBM-ASCII
+#define CHARSET_MODE7	MODE7		// MODE 7
 #define CHARSET_UTF8    UTF8
 #define CHARSET_CP437   0
 
@@ -694,6 +695,7 @@ typedef enum {                      /* Values for xtrn_t.event				*/
 #define P_REMOTE    (1 << 18)     /* Only print when online == ON_REMOTE		*/
 #define P_INDENT    (1 << 19)     /* Indent lines to current cursor column	*/
 #define P_ATCODES   (1 << 20)     /* Trusted @-codes in formatted string		*/
+#define P_MODE7		(1 << 21)     /* Message is native Mode 7					*/
 
 /* Bits in 'mode' for listfiles             */
 #define FL_ULTIME   (1 << 0)      /* List files by upload time                */
diff --git a/src/sbbs3/scfg/scfgsrvr.c b/src/sbbs3/scfg/scfgsrvr.c
index 4e870ce2c329fc8f21cea5a16772890ab52b3cd1..b52ce44848a1a2d0c40a7a0798025b57f6ed6be4 100644
--- a/src/sbbs3/scfg/scfgsrvr.c
+++ b/src/sbbs3/scfg/scfgsrvr.c
@@ -557,6 +557,8 @@ static void termsrvr_cfg(void)
 		snprintf(opt[i++], MAX_OPLN, "%-30s%s", "40 Column PETSCII Support", startup.pet40_port ? str : strDisabled );
 		snprintf(str, sizeof str, "Port %u", startup.pet80_port);
 		snprintf(opt[i++], MAX_OPLN, "%-30s%s", "80 Column PETSCII Support", startup.pet80_port  ? str : strDisabled);
+		snprintf(str, sizeof str, "Port %u", startup.mode7_port);
+		snprintf(opt[i++], MAX_OPLN, "%-30s%s", "BBC Mode 7 Support", startup.mode7_port  ? str : strDisabled);
 		snprintf(opt[i++], MAX_OPLN, "%-30s%s", "DOS Program Support", startup.options & BBS_OPT_NO_DOS ? "No" : "Yes");
 		snprintf(opt[i++], MAX_OPLN, "%-30s%s", "Max Concurrent Connections", maximum(startup.max_concurrent_connections));
 		snprintf(opt[i++], MAX_OPLN, "%-30s%s", "Max Login Inactivity", vduration(startup.max_login_inactivity));
@@ -621,9 +623,14 @@ static void termsrvr_cfg(void)
 					startup.pet80_port = atoi(str);
 				break;
 			case 8:
-				startup.options ^= BBS_OPT_NO_DOS;
+				SAFEPRINTF(str, "%u", startup.mode7_port);
+				if (uifc.input(WIN_MID | WIN_SAV, 0, 0, "BBC Mode 7 Port", str, 5, K_NUMBER | K_EDIT) > 0)
+					startup.mode7_port = atoi(str);
 				break;
 			case 9:
+				startup.options ^= BBS_OPT_NO_DOS;
+				break;
+			case 10:
 				SAFECOPY(str, maximum(startup.max_concurrent_connections));
 				if (uifc.input(WIN_MID | WIN_SAV, 0, 0, "Maximum Concurrent (Unauthenticated) Connections", str, 10, K_EDIT) > 0)
 					startup.max_concurrent_connections = atoi(str);
@@ -637,7 +644,7 @@ static void termsrvr_cfg(void)
 		"`Maximum User Inactivity` setting in `System->Advanced Options`.\n" \
 		"Normally, if enabled, this socket inactivity duration should be `longer`\n" \
 		"than the `Maximum User Inactivity` setting in `System->Advanced Options`.\n"
-			case 10:
+			case 11:
 				uifc.helpbuf =
 					"`Maximum Socket Inactivity at Login:`\n"
 					"\n"
@@ -651,7 +658,7 @@ static void termsrvr_cfg(void)
 				if (uifc.input(WIN_MID | WIN_SAV, 0, 0, "Maximum Socket Inactivity at Login", str, 10, K_EDIT) > 0)
 					startup.max_login_inactivity = (uint16_t)parse_duration(str);
 				break;
-			case 11:
+			case 12:
 				uifc.helpbuf =
 					"`Maximum Socket Inactivity at New User Registration:`\n"
 					"\n"
@@ -665,7 +672,7 @@ static void termsrvr_cfg(void)
 				if (uifc.input(WIN_MID | WIN_SAV, 0, 0, "Maximum Socket Inactivity at New User Registration", str, 10, K_EDIT) > 0)
 					startup.max_newuser_inactivity = (uint16_t)parse_duration(str);
 				break;
-			case 12:
+			case 13:
 				uifc.helpbuf =
 					"`Maximum Socket Inactivity during User Session:`\n"
 					"\n"
@@ -681,34 +688,34 @@ static void termsrvr_cfg(void)
 				if (uifc.input(WIN_MID | WIN_SAV, 0, 0, "Maximum Socket Inactivity during User Session", str, 10, K_EDIT) > 0)
 					startup.max_session_inactivity = (uint16_t)parse_duration(str);
 				break;
-			case 13:
+			case 14:
 				SAFEPRINTF(str, "%u", startup.outbuf_drain_timeout);
 				if (uifc.input(WIN_MID | WIN_SAV, 0, 0, "Output Buffer Drain Timeout (milliseconds)", str, 5, K_NUMBER | K_EDIT) > 0)
 					startup.outbuf_drain_timeout = atoi(str);
 				break;
-			case 14:
+			case 15:
 				startup.options ^= BBS_OPT_NO_EVENTS;
 				break;
-			case 15:
+			case 16:
 				if (startup.options & BBS_OPT_NO_EVENTS)
 					break;
 				startup.options ^= BBS_OPT_NO_QWK_EVENTS;
 				break;
-			case 16:
+			case 17:
 				if (startup.options & BBS_OPT_NO_EVENTS)
 					break;
 				uifc.list(WIN_MID | WIN_SAV, 0, 0, 0, &startup.event_log_level, 0, "Event Log Level", iniLogLevelStringList());
 				break;
-			case 17:
+			case 18:
 				startup.options ^= BBS_OPT_NO_HOST_LOOKUP;
 				break;
-			case 18:
+			case 19:
 				getar("Terminal Server Login", startup.login_ars);
 				break;
-			case 19:
+			case 20:
 				js_startup_cfg(&startup.js);
 				break;
-			case 20:
+			case 21:
 				login_attempt_cfg(&startup.login_attempt);
 				break;
 			default:
diff --git a/src/sbbs3/startup.h b/src/sbbs3/startup.h
index bdefe555fa193011286cd3cfa2cb413fa11f5562..58d70b865b0b061d800183465725120bec13e4d7 100644
--- a/src/sbbs3/startup.h
+++ b/src/sbbs3/startup.h
@@ -129,6 +129,7 @@ typedef struct {
 	uint16_t rlogin_port;
 	uint16_t pet40_port;            // 40-column PETSCII terminal server
 	uint16_t pet80_port;            // 80-column PETSCII terminal server
+	uint16_t mode7_port;			// 40-column MODE7 terminal server
 	uint16_t ssh_port;
 	uint16_t ssh_connect_timeout;
 	int ssh_error_level;
diff --git a/src/sbbs3/text.h b/src/sbbs3/text.h
index b7097f503eed638ef00d6fed431f9992b659714b..548c2785b4a2b4657e58cdec9e733bd89e6bcfbc 100644
--- a/src/sbbs3/text.h
+++ b/src/sbbs3/text.h
@@ -954,6 +954,8 @@ enum text {
 	,QWKTagLineFmt
 	,QWKControlCommand
 	,QWKBadControlCommand
+	,Mode7TerminalDetected
+	,Mode7TerminalQ
 
 	,TOTAL_TEXT
 };
diff --git a/src/sbbs3/text_defaults.c b/src/sbbs3/text_defaults.c
index 6c568a1ec92a09c016bd58b7e79df623d1717d92..4929b181ae183e41338039a77992e5f9c61b8308 100644
--- a/src/sbbs3/text_defaults.c
+++ b/src/sbbs3/text_defaults.c
@@ -1507,4 +1507,6 @@ const char * const text_defaults[TOTAL_TEXT]={
 		"\x25\x73\x0d\x0a" // 936 QWKControlCommand
 	,"\x55\x6e\x72\x65\x63\x6f\x67\x6e\x69\x7a\x65\x64\x20\x43\x6f\x6e\x74\x72\x6f\x6c\x20\x43\x6f\x6d\x6d\x61\x6e\x64\x21\x01\x6e\x0d"
 		"\x0a" // 937 QWKBadControlCommand
+	,"\x4d\x6f\x64\x65\x20\x37\x20\x74\x65\x72\x6d\x69\x6e\x61\x6c\x20\x64\x65\x74\x65\x63\x74\x65\x64" // 938 Mode7TerminalDetected
+	,"\x41\x72\x65\x20\x79\x6f\x75\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x4d\x6f\x64\x65\x20\x37\x20\x74\x65\x72\x6d\x69\x6e\x61\x6c" // 939 Mode7TerminalQ
 };
diff --git a/src/sbbs3/text_id.c b/src/sbbs3/text_id.c
index abf977c9445570075c159292bff0b606057a8b66..213aaf14910484fdbf7ab7e5dedf661c15e9e61b 100644
--- a/src/sbbs3/text_id.c
+++ b/src/sbbs3/text_id.c
@@ -938,4 +938,6 @@ const char* const text_id[]={
 	,"QWKTagLineFmt"
 	,"QWKControlCommand"
 	,"QWKBadControlCommand"
+	,"Mode7TerminalDetected"
+	,"Mode7TerminalQ"
 };
diff --git a/src/sbbs3/userdat.c b/src/sbbs3/userdat.c
index 5d28ebe2d623d03a4696546f1268e02b7851b8a2..9049296eb10243cf73eeef145363c52200663bd3 100644
--- a/src/sbbs3/userdat.c
+++ b/src/sbbs3/userdat.c
@@ -2177,6 +2177,12 @@ static bool ar_exp(scfg_t* cfg, uchar **ptrptr, user_t* user, client_t* client)
 				else
 					result = !not;
 				break;
+			case AR_MODE7:
+				if (user == NULL || (user->misc & CHARSET_FLAGS) != CHARSET_MODE7)
+					result = not;
+				else
+					result = !not;
+				break;
 			case AR_ASCII:
 				if (user == NULL || (user->misc & CHARSET_FLAGS) != CHARSET_ASCII)
 					result = not;
diff --git a/src/sbbs3/useredit.cpp b/src/sbbs3/useredit.cpp
index eddc505f0c8ae7079745aea518b8998185ddcecb..77d9366f6c0fff9fb48cb4c007421ccb2b1db702 100644
--- a/src/sbbs3/useredit.cpp
+++ b/src/sbbs3/useredit.cpp
@@ -880,7 +880,7 @@ void sbbs_t::user_config(user_t* user)
 			case 'T':
 				if (yesno(text[AutoTerminalQ])) {
 					user->misc |= AUTOTERM;
-					user->misc &= ~(ANSI | RIP | PETSCII | UTF8);
+					user->misc &= ~(ANSI | RIP | PETSCII | UTF8 | MODE7);
 					if (user == &useron)
 						user->misc |= autoterm;
 				}
diff --git a/src/sbbs3/xtrn.cpp b/src/sbbs3/xtrn.cpp
index 69b8ef8cd43ae9b28d5c2094b0288c463cf02255..152d43e00fc9d1f54dc7d70556f135ab33cc3dd1 100644
--- a/src/sbbs3/xtrn.cpp
+++ b/src/sbbs3/xtrn.cpp
@@ -214,6 +214,13 @@ static void petscii_convert(BYTE* buf, uint len)
 	}
 }
 
+static void mode7_convert(BYTE* buf, uint len)
+{
+	for (uint i = 0; i < len; i++) {
+		buf[i] = cp437_to_mode7(buf[i]);
+	}
+}
+
 static BYTE* cp437_to_utf8(BYTE* input, size_t& len, BYTE* outbuf, size_t maxlen)
 {
 	size_t outlen = 0;
@@ -1961,6 +1968,8 @@ int sbbs_t::external(const char* cmdline, int mode, const char* startup_dir)
 				}
 				if (term_supports(PETSCII))
 					petscii_convert(bp, output_len);
+				else if (term_supports(MODE7))
+					mode7_convert(bp, output_len);
 				else if (term_supports(UTF8))
 					bp = cp437_to_utf8(bp, output_len, utf8_buf, sizeof utf8_buf);
 			}