diff --git a/src/sbbs3/atcodes.cpp b/src/sbbs3/atcodes.cpp
index 525de32cf6e4c2e25769681c2fafd0b1eb9da363..44ce88aa80ae056bc2132753fad0becec29f05a7 100644
--- a/src/sbbs3/atcodes.cpp
+++ b/src/sbbs3/atcodes.cpp
@@ -249,8 +249,9 @@ static const char* getpath(scfg_t* cfg, const char* path)
 	return path;
 }
 
-const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, int* pmode, bool centered, JSObject* obj)
+const char* sbbs_t::atcode(const char* sp, char* str, size_t maxlen, int* pmode, bool centered, JSObject* obj)
 {
+	char	tmp[128];
 	char*	tp = NULL;
 	int		i;
 	uint	ugrp;
@@ -692,12 +693,12 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, int* pmode, bool
 	}
 
 	if(strncmp(sp, "DATE:", 5) == 0 || strncmp(sp, "TIME:", 5) == 0) {
-		sp += 5;
-		c_unescape_str(sp);
+		SAFECOPY(tmp, sp + 5);
+		c_unescape_str(tmp);
 		now = time(NULL);
 		memset(&tm, 0, sizeof(tm));
 		localtime_r(&now, &tm);
-		strftime(str, maxlen, sp, &tm);
+		strftime(str, maxlen, tmp, &tm);
 		return str;
 	}
 
@@ -871,12 +872,12 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, int* pmode, bool
 	}
 
 	if(strncmp(sp, "FILL:", 5) == 0) {
-		sp += 5;
+		SAFECOPY(tmp, sp + 5);
 		int margin = centered ? column : 1;
 		if(margin < 1) margin = 1;
-		c_unescape_str(sp);
-		while(*sp && online && column < cols - margin)
-			bputs(sp, P_TRUNCATE);
+		c_unescape_str(tmp);
+		while(*tmp && online && column < cols - margin)
+			bputs(tmp, P_TRUNCATE);
 		return nulstr;
 	}
 
@@ -1012,14 +1013,14 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, int* pmode, bool
 		return format_birthdate(&cfg, useron.birth, str, maxlen);
 
 	if(strncmp(sp, "BDATE:", 6) == 0 || strncmp(sp, "BIRTH:", 6) == 0) {
-		sp += 6;
-		c_unescape_str(sp);
+		SAFECOPY(tmp, sp + 6);
+		c_unescape_str(tmp);
 		memset(&tm,0,sizeof(tm));
 		tm.tm_year = getbirthyear(useron.birth) - 1900;
 		tm.tm_mon = getbirthmonth(&cfg, useron.birth) - 1;
 		tm.tm_mday = getbirthday(&cfg, useron.birth);
 		mktime(&tm);
-		strftime(str, maxlen, sp, &tm);
+		strftime(str, maxlen, tmp, &tm);
 		return str;
 	}
 
@@ -1043,12 +1044,12 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, int* pmode, bool
 		return(unixtodstr(&cfg,useron.pwmod,str));
 
 	if(strncmp(sp, "PWDATE:", 7) == 0) {
-		sp += 7;
-		c_unescape_str(sp);
+		SAFECOPY(tmp, sp + 7);
+		c_unescape_str(tmp);
 		memset(&tm, 0, sizeof(tm));
 		time_t date = useron.pwmod;
 		localtime_r(&date, &tm);
-		strftime(str, maxlen, sp, &tm);
+		strftime(str, maxlen, tmp, &tm);
 		return str;
 	}
 
@@ -1061,12 +1062,12 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, int* pmode, bool
 		return(unixtodstr(&cfg,useron.firston,str));
 
 	if(strncmp(sp, "SINCE:", 6) == 0) {
-		sp += 6;
-		c_unescape_str(sp);
+		SAFECOPY(tmp, sp + 6);
+		c_unescape_str(tmp);
 		memset(&tm, 0, sizeof(tm));
 		time_t date = useron.firston;
 		localtime_r(&date, &tm);
-		strftime(str, maxlen, sp, &tm);
+		strftime(str, maxlen, tmp, &tm);
 		return str;
 	}
 
@@ -1135,12 +1136,12 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, int* pmode, bool
 		return(unixtodstr(&cfg,useron.laston,str));
 
 	if(strncmp(sp, "LASTON:", 7) == 0) {
-		sp += 7;
-		c_unescape_str(sp);
+		SAFECOPY(tmp, sp + 7);
+		c_unescape_str(tmp);
 		memset(&tm, 0, sizeof(tm));
 		time_t date = useron.laston;
 		localtime_r(&date, &tm);
-		strftime(str, maxlen, sp, &tm);
+		strftime(str, maxlen, tmp, &tm);
 		return str;
 	}
 
@@ -1165,12 +1166,12 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, int* pmode, bool
 		return(unixtodstr(&cfg,useron.firston,str));
 
 	if(strncmp(sp, "FIRSTON:", 8) == 0) {
-		sp += 8;
-		c_unescape_str(sp);
+		SAFECOPY(tmp, sp + 8);
+		c_unescape_str(tmp);
 		memset(&tm, 0, sizeof(tm));
 		time_t date = useron.firston;
 		localtime_r(&date, &tm);
-		strftime(str, maxlen, sp, &tm);
+		strftime(str, maxlen, tmp, &tm);
 		return str;
 	}
 
@@ -1343,12 +1344,12 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, int* pmode, bool
 		return(unixtodstr(&cfg,(time32_t)ns_time,str));
 
 	if(strncmp(sp, "LASTNEW:", 8) == 0) {
-		sp += 8;
-		c_unescape_str(sp);
+		SAFECOPY(tmp, sp + 8);
+		c_unescape_str(tmp);
 		memset(&tm, 0, sizeof(tm));
 		time_t date = ns_time;
 		localtime_r(&date, &tm);
-		strftime(str, maxlen, sp, &tm);
+		strftime(str, maxlen, tmp, &tm);
 		return str;
 	}
 
@@ -1415,12 +1416,12 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, int* pmode, bool
 	if(strncmp(sp, "EXPDATE:", 8) == 0) {
 		if(!useron.expire)
 			return nulstr;
-		sp += 8;
-		c_unescape_str(sp);
+		SAFECOPY(tmp, sp + 8);
+		c_unescape_str(tmp);
 		memset(&tm, 0, sizeof(tm));
 		time_t date = useron.expire;
 		localtime_r(&date, &tm);
-		strftime(str, maxlen, sp, &tm);
+		strftime(str, maxlen, tmp, &tm);
 		return str;
 	}
 
@@ -1578,10 +1579,10 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, int* pmode, bool
 	}
 
 	if(!strncmp(sp,"GOTOXY:",7)) {
-		tp=strchr(sp,',');
-		if(tp!=NULL) {
-			tp++;
-			cursor_xy(atoi(sp+7),atoi(tp));
+		const char* cp=strchr(sp,',');
+		if(cp!=NULL) {
+			cp++;
+			cursor_xy(atoi(sp+7),atoi(cp));
 		}
 		return(nulstr);
 	}
@@ -1887,7 +1888,6 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, int* pmode, bool
 		if(current_msg->from_ext!=NULL)
 			safe_snprintf(str,maxlen,"%s #%s",current_msg_from,current_msg->from_ext);
 		else if(current_msg->from_net.addr != NULL) {
-			char tmp[128];
 			safe_snprintf(str,maxlen,"%s (%s)",current_msg_from
 				,smb_netaddrstr(&current_msg->from_net,tmp));
 		} else
@@ -2191,3 +2191,29 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, int* pmode, bool
 
 	return gettext(sp);
 }
+
+char* sbbs_t::expand_atcodes(const char* src, char* buf, size_t size)
+{
+	char* dst = buf;
+	char* end = dst + size;
+
+	while (*src != '\0' && dst < end) {
+		if (*src == '@') {
+			char str[32];
+			SAFECOPY(str, src + 1);
+			char* at = strchr(str, '@');
+			const char* sp = strchr(str, ' ');
+			if (at != NULL && (sp == NULL || sp > at)) {
+				char tmp[128];
+				*at = '\0';
+				src += strlen(str) + 2;
+				dst += strlcpy(dst, atcode(str, tmp, sizeof tmp, NULL, false, NULL), end - dst);
+				continue;
+			}
+		}
+		*(dst++) = *(src++);
+	}
+	*dst = '\0';
+	return buf;
+}
+
diff --git a/src/sbbs3/con_out.cpp b/src/sbbs3/con_out.cpp
index ade51372c5228f01d5eb379bf186670ce415025b..b4699ac94571bddca95d65b112fdc870962d4df1 100644
--- a/src/sbbs3/con_out.cpp
+++ b/src/sbbs3/con_out.cpp
@@ -701,8 +701,7 @@ int sbbs_t::outchar(char ch)
 		return 0;
 
 	if((console&CON_R_ECHOX) && (uchar)ch>=' ' && outchar_esc == ansiState_none) {
-		ch=text[YNQP][3];
-		if(text[YNQP][2]==0 || ch==0) ch='X';
+		ch = *text[PasswordChar];
 	}
 	if(ch==FF)
 		clearscreen(term);
diff --git a/src/sbbs3/getkey.cpp b/src/sbbs3/getkey.cpp
index 024f3ab44f2f23d779e8c0e8691eff544157ddfb..fef142eb83c69d25274d367d8e38297a43e79e70 100644
--- a/src/sbbs3/getkey.cpp
+++ b/src/sbbs3/getkey.cpp
@@ -173,25 +173,28 @@ char sbbs_t::getkey(int mode)
 /****************************************************************************/
 /* Outputs a string highlighting characters preceded by a tilde             */
 /****************************************************************************/
-void sbbs_t::mnemonics(const char *str)
+void sbbs_t::mnemonics(const char *instr)
 {
     const char *ctrl_a_codes;
     size_t l;
 
-	if(!strchr(str,'~')) {
-		mnestr=str;
-		bputs(str);
+	if(!strchr(instr,'~')) {
+		mnestr= instr;
+		bputs(instr);
 		return; 
 	}
-	ctrl_a_codes=strchr(str,1);
+	ctrl_a_codes=strchr(instr,1);
 	if(!ctrl_a_codes) {
-		if(str[0]=='@' && str[strlen(str)-1]=='@' && !strchr(str,' ')) {
-			mnestr=str;
-			bputs(str);
+		const char* last = lastchar(instr);
+		if(instr[0] == '@' && *last == '@' && strchr(instr + 1, '@') == last && strchr(instr, ' ') == NULL) {
+			mnestr= instr;
+			bputs(instr);
 			return; 
 		}
 		attr(cfg.color[clr_mnelow]); 
 	}
+	char str[256];
+	expand_atcodes(instr, str, sizeof str);
 	l=0L;
 	int term = term_supports();
 
@@ -235,13 +238,6 @@ void sbbs_t::mnemonics(const char *str)
 					break;
 				ctrl_a(str[l++]);
 			} else {
-				if(str[l] == '@') {
-					int i = show_atcode(str + l);
-					if(i) {
-						l += i;
-						continue;
-					}
-				}
 				outchar(str[l++]);
 			}
 		} 
diff --git a/src/sbbs3/js_bbs.cpp b/src/sbbs3/js_bbs.cpp
index 4a0273943a3225773f260e6f48760c3ef9a85076..2ec08248c5cd9fbe9825e3098a8bde87cca9d9c2 100644
--- a/src/sbbs3/js_bbs.cpp
+++ b/src/sbbs3/js_bbs.cpp
@@ -1706,6 +1706,33 @@ js_atcode(JSContext *cx, uintN argc, jsval *arglist)
 	return(JS_TRUE);
 }
 
+static JSBool
+js_expand_atcodes(JSContext* cx, uintN argc, jsval* arglist)
+{
+	jsval* argv = JS_ARGV(cx, arglist);
+	sbbs_t* sbbs;
+	char	result[256] = "";
+	char*	instr;
+	jsrefcount	rc;
+
+	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
+		return JS_FALSE;
+
+	if (!js_argc(cx, argc, 1))
+		return JS_FALSE;
+
+	JSVALUE_TO_MSTRING(cx, argv[0], instr, NULL);
+	if (instr == NULL)
+		return JS_FALSE;
+
+	rc = JS_SUSPENDREQUEST(cx);
+	sbbs->expand_atcodes(instr, result, sizeof result);
+	free(instr);
+	JS_RESUMEREQUEST(cx, rc);
+	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, result)));
+
+	return JS_TRUE;
+}
 
 static JSBool
 js_logkey(JSContext *cx, uintN argc, jsval *arglist)
@@ -4386,18 +4413,25 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	,JSDOCSTR("Returns @-code value, specified <i>code</i> string does not include @ character delimiters")
 	,310
 	},
+	{"expand_atcodes",	js_expand_atcodes,	1,	JSTYPE_STRING,	JSDOCSTR("string")
+	,JSDOCSTR("Returns string with @-code expanded values (formatting and some @-codes are not supported)")
+	,320
+	},
 	/* text.dat */
-	{"text",			js_text,			1,	JSTYPE_STRING,	JSDOCSTR("line_number")
-	,JSDOCSTR("Returns specified text string from text.dat")
+	{"text",			js_text,			1,	JSTYPE_STRING,	JSDOCSTR("index_number")
+	,JSDOCSTR("Returns current text string (specified via 1-based string index number)"
+		"from text.dat/text.ini or replacement text or <i>null</i> upon error<br>"
+		"<i>New in v3.20:</i> Use <tt>bbs.text.<i>ID</i><tt> to obtain a text string index number from its corresponding ID (name)"
+	)
 	,310
 	},
-	{"replace_text",	js_replace_text,	2,	JSTYPE_BOOLEAN,	JSDOCSTR("line_number, text")
-	,JSDOCSTR("Replaces specified text string in memory")
+	{"replace_text",	js_replace_text,	2,	JSTYPE_BOOLEAN,	JSDOCSTR("index_number, text")
+	,JSDOCSTR("Replaces specified text.dat/text.ini string in memory")
 	,310
 	},
-	{"revert_text",		js_revert_text,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("[line_number=<i>all</i>]")
-	,JSDOCSTR("Reverts specified text string to original text string; "
-		"if <i>line_number</i> unspecified, reverts all text lines")
+	{"revert_text",		js_revert_text,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("[index_number=<i>all</i>]")
+	,JSDOCSTR("Reverts specified text string to original text.dat/text.ini string; "
+		"if <i>index_number</i> unspecified, reverts all text lines")
 	,310
 	},
 	{"load_text",		js_load_text,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("base_filename")
@@ -4885,6 +4919,8 @@ JSObject* js_CreateBbsObject(JSContext* cx, JSObject* parent)
 	if((mods=JS_DefineObject(cx, obj, "mods", NULL, NULL ,JSPROP_ENUMERATE))==NULL)
 		return(NULL);
 
+	js_CreateTextProperties(cx, obj);
+
 #ifdef BUILD_JSDOCS
 	js_DescribeSyncObject(cx,mods,"Global repository for 3rd party modifications",312);
 	js_DescribeSyncObject(cx,obj,"Controls the Terminal Server (traditional BBS) experience",310);
diff --git a/src/sbbs3/js_console.cpp b/src/sbbs3/js_console.cpp
index f08a382a173b4d811b385489c321fd846e34cea3..89e45f7f3f5dc7dde6d9204a921a9d82651e9828 100644
--- a/src/sbbs3/js_console.cpp
+++ b/src/sbbs3/js_console.cpp
@@ -63,6 +63,13 @@ enum {
 	,CON_PROP_OUTBUF_SPACE
 	,CON_PROP_KEYBUF_LEVEL
 	,CON_PROP_KEYBUF_SPACE
+	,CON_PROP_YES_KEY
+	,CON_PROP_NO_KEY
+	,CON_PROP_QUIT_KEY
+	,CON_PROP_ALL_KEY
+	,CON_PROP_LIST_KEY
+	,CON_PROP_NEXT_KEY
+	,CON_PROP_PREV_KEY
 
 	,CON_PROP_OUTPUT_RATE
 };
@@ -73,7 +80,7 @@ static JSBool js_console_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 	jsval		idval;
 	int32		val;
     jsint       tiny;
-	JSString*	js_str;
+	JSString*	js_str = NULL;
 	sbbs_t*		sbbs;
 
 	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, obj, &js_console_class))==NULL)
@@ -125,18 +132,15 @@ static JSBool js_console_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 		case CON_PROP_TERMINAL:
 			if((js_str=JS_NewStringCopyZ(cx, sbbs->terminal))==NULL)
 				return(JS_FALSE);
-			*vp = STRING_TO_JSVAL(js_str);
-			return(JS_TRUE);
+			break;
 		case CON_PROP_TERM_TYPE:
 			if((js_str=JS_NewStringCopyZ(cx, sbbs->term_type()))==NULL)
 				return(JS_FALSE);
-			*vp = STRING_TO_JSVAL(js_str);
-			return(JS_TRUE);
+			break;
 		case CON_PROP_CHARSET:
 			if((js_str=JS_NewStringCopyZ(cx, sbbs->term_charset()))==NULL)
 				return(JS_FALSE);
-			*vp = STRING_TO_JSVAL(js_str);
-			return(JS_TRUE);
+			break;
 		case CON_PROP_CTERM_VERSION:
 			val=sbbs->cterm_version;
 			break;
@@ -168,13 +172,11 @@ static JSBool js_console_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 		case CON_PROP_WORDWRAP:
 			if((js_str=JS_NewStringCopyZ(cx, sbbs->wordwrap))==NULL)
 				return(JS_FALSE);
-			*vp = STRING_TO_JSVAL(js_str);
-			return(JS_TRUE);
+			break;
 		case CON_PROP_QUESTION:
 			if((js_str=JS_NewStringCopyZ(cx, sbbs->question))==NULL)
 				return(JS_FALSE);
-			*vp = STRING_TO_JSVAL(js_str);
-			return(JS_TRUE);
+			break;
 		case CON_PROP_CTRLKEY_PASSTHRU:
 			val=sbbs->cfg.ctrlkey_passthru;
 			break;
@@ -200,11 +202,43 @@ static JSBool js_console_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 			val = sbbs->keybuf_space();
 			break;
 
+		case CON_PROP_YES_KEY:
+			if ((js_str = JS_NewStringCopyN(cx, sbbs->text[Yes], 1)) == NULL)
+				return JS_FALSE;
+			break;
+		case CON_PROP_NO_KEY:
+			if ((js_str = JS_NewStringCopyN(cx, sbbs->text[No], 1)) == NULL)
+				return JS_FALSE;
+			break;
+		case CON_PROP_QUIT_KEY:
+			if ((js_str = JS_NewStringCopyN(cx, sbbs->text[Quit], 1)) == NULL)
+				return JS_FALSE;
+			break;
+		case CON_PROP_ALL_KEY:
+			if ((js_str = JS_NewStringCopyN(cx, sbbs->text[All], 1)) == NULL)
+				return JS_FALSE;
+			break;
+		case CON_PROP_LIST_KEY:
+			if ((js_str = JS_NewStringCopyN(cx, sbbs->text[List], 1)) == NULL)
+				return JS_FALSE;
+			break;
+		case CON_PROP_NEXT_KEY:
+			if ((js_str = JS_NewStringCopyN(cx, sbbs->text[Next], 1)) == NULL)
+				return JS_FALSE;
+			break;
+		case CON_PROP_PREV_KEY:
+			if ((js_str = JS_NewStringCopyN(cx, sbbs->text[Previous], 1)) == NULL)
+				return JS_FALSE;
+			break;
+
 		default:
 			return(JS_TRUE);
 	}
 
-	*vp = INT_TO_JSVAL(val);
+	if(js_str != NULL)
+		*vp = STRING_TO_JSVAL(js_str);
+	else
+		*vp = INT_TO_JSVAL(val);
 
 	return(JS_TRUE);
 }
@@ -393,6 +427,13 @@ static jsSyncPropertySpec js_console_properties[] = {
 	{	"output_rate"		,CON_PROP_OUTPUT_RATE		,JSPROP_ENUMERATE, 31702},
 	{	"keyboard_buffer_level",CON_PROP_KEYBUF_LEVEL	,JSPROP_ENUMERATE|JSPROP_READONLY, 31800},
 	{	"keyboard_buffer_space",CON_PROP_KEYBUF_SPACE	,JSPROP_ENUMERATE|JSPROP_READONLY, 31800},
+	{	"yes_key"			,CON_PROP_YES_KEY			,JSPROP_ENUMERATE|JSPROP_READONLY, 32000},
+	{	"no_key"			,CON_PROP_NO_KEY			,JSPROP_ENUMERATE|JSPROP_READONLY, 32000},
+	{	"quit_key"			,CON_PROP_QUIT_KEY			,JSPROP_ENUMERATE|JSPROP_READONLY, 32000},
+	{	"all_key"			,CON_PROP_ALL_KEY			,JSPROP_ENUMERATE|JSPROP_READONLY, 32000},
+	{	"list_key"			,CON_PROP_LIST_KEY			,JSPROP_ENUMERATE|JSPROP_READONLY, 32000},
+	{	"next_key"			,CON_PROP_NEXT_KEY			,JSPROP_ENUMERATE|JSPROP_READONLY, 32000},
+	{	"prev_key"			,CON_PROP_PREV_KEY			,JSPROP_ENUMERATE|JSPROP_READONLY, 32000},
 	{0}
 };
 
@@ -443,6 +484,13 @@ static const char* con_prop_desc[] = {
 	,"Emulated serial data output rate, in bits-per-second (0 = unlimited)"
 	,"Number of characters currently in the keyboard input buffer (from <tt>ungetstr</tt>) - <small>READ ONLY</small>"
 	,"Number of character spaces available in the keyboard input buffer - <small>READ ONLY</small>"
+	,"Key associated with a positive acknowledgment (e.g. 'Y') - <small>READ ONLY</small>"
+	,"Key associated with a negative acknowledgment (e.g. 'N') - <small>READ ONLY</small>"
+	,"Key associated with a exiting a menu (e.g. 'Q') - <small>READ ONLY</small>"
+	,"Key associated with selecting all available options (e.g. 'A') - <small>READ ONLY</small>"
+	,"Key associated with listing all available options (e.g. 'L') - <small>READ ONLY</small>"
+	,"Key associated with selecting next available option (e.g. 'N') - <small>READ ONLY</small>"
+	,"Key associated with selecting previous available option (e.g. 'P') - <small>READ ONLY</small>"
 	,NULL
 };
 #endif
diff --git a/src/sbbs3/js_system.c b/src/sbbs3/js_system.c
index 08ff799056a02cece41bd1f3d6a1243beb761ff4..052afc291b673ad70be0fe0a842883f8988e5b3e 100644
--- a/src/sbbs3/js_system.c
+++ b/src/sbbs3/js_system.c
@@ -2296,8 +2296,8 @@ static jsSyncMethodSpec js_system_functions[] = {
 		"returns <i>true</i> on success")
 	,315
 	},
-	{"text",			js_text,			1,	JSTYPE_STRING,	JSDOCSTR("number")
-	,JSDOCSTR("Returns specified text string from text.dat (like <tt>bbs.text()</tt>) or returns <i>null</i> upon error")
+	{"text",			js_text,			1,	JSTYPE_STRING,	JSDOCSTR("index_number")
+	,JSDOCSTR("Returns specified text string (see <tt>bbs.text()</tt> for details)")
 	,31802
 	},
 	{0}
@@ -2761,6 +2761,22 @@ static void js_system_finalize(JSContext *cx, JSObject *obj)
 	JS_SetPrivate(cx, obj, NULL);
 }
 
+JSBool js_CreateTextProperties(JSContext* cx, JSObject* parent)
+{
+	jsval val;
+
+	if (!JS_GetProperty(cx, parent, "text", &val))
+		return JS_FALSE;
+
+	JSObject* text = JSVAL_TO_OBJECT(val);
+	for (int i = 0; i < TOTAL_TEXT; ++i) {
+		val = INT_TO_JSVAL(i + 1);
+		if(!JS_SetProperty(cx, text, text_id[i], &val))
+			return JS_FALSE;
+	}
+	return JS_TRUE;
+}
+
 JSClass js_system_class = {
      "System"				/* name			*/
     ,JSCLASS_HAS_PRIVATE	/* flags		*/
@@ -2819,6 +2835,8 @@ JSObject* js_CreateSystemObject(JSContext* cx, JSObject* parent
 	if(!JS_SetProperty(cx, sysobj, "uptime", &val))
 		return(NULL);
 
+	js_CreateTextProperties(cx, sysobj);
+
 #ifdef BUILD_JSDOCS
 	js_DescribeSyncObject(cx,sysobj,"Global system-related properties and methods",310);
 	js_CreateArrayOfStrings(cx, sysobj, "_property_desc_list", sys_prop_desc, JSPROP_READONLY);
diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h
index 66bb1f73aa1c1717575b8c6ff36a4f16c0739d8c..d856cbe062b18c02ae1f23e33ec291348eea5366 100644
--- a/src/sbbs3/sbbs.h
+++ b/src/sbbs3/sbbs.h
@@ -526,13 +526,15 @@ public:
 	/*********************************/
 	/* Color Configuration Variables */
 	/*********************************/
-	char 	*text[TOTAL_TEXT]{};			/* Text from ctrl\text.dat */
-	char 	*text_sav[TOTAL_TEXT]{};		/* Text from ctrl\text.dat */
-	char	yes_key(void) { return toupper(text[YNQP][0]); }
-	char	no_key(void) { return toupper(text[YNQP][1]); }
-	char	quit_key(void) { return toupper(text[YNQP][2]); }
-	char	all_key(void) { return toupper(text[AllKey][0]); }
-	char	list_key(void) { return toupper(text[ListKey][0]); }
+	char 	*text[TOTAL_TEXT]{};			/* Text from text.dat/text.ini */
+	char 	*text_sav[TOTAL_TEXT]{};		/* Text from text.dat/text.ini */
+	char	yes_key(void) { return toupper(*text[Yes]); }
+	char	no_key(void) { return toupper(*text[No]); }
+	char	quit_key(void) { return toupper(*text[Quit]); }
+	char	all_key(void) { return toupper(*text[All]); }
+	char	list_key(void) { return toupper(*text[List]); }
+	char	next_key(void) { return toupper(*text[Next]); }
+	char	prev_key(void) { return toupper(*text[Previous]); }
 
 	char 	dszlog[127]{};	/* DSZLOG environment variable */
     int     keybuftop=0, keybufbot=0;    /* Keyboard input buffer pointers (for ungetkey) */
@@ -968,7 +970,8 @@ public:
 
 	/* atcodes.cpp */
 	int		show_atcode(const char *code, JSObject* obj = NULL);
-	const char*	atcode(char* sp, char* str, size_t maxlen, int* pmode = NULL, bool centered = false, JSObject* obj = NULL);
+	const char*	atcode(const char* sp, char* str, size_t maxlen, int* pmode = NULL, bool centered = false, JSObject* obj = NULL);
+	char* expand_atcodes(const char* src, char* buf, size_t size);
 
 	/* getnode.cpp */
 	int		getsmsg(int usernumber, bool clearline = false);
@@ -1420,6 +1423,7 @@ extern "C" {
 													,scfg_t* cfg, time_t uptime
 													,char* host_name
 													,char* socklib_desc);
+	DLLEXPORT JSBool	js_CreateTextProperties(JSContext* cx, JSObject* parent);
 
 	/* js_client.c */
 #ifdef USE_CRYPTLIB
diff --git a/src/sbbs3/scansubs.cpp b/src/sbbs3/scansubs.cpp
index 4b9b8a85798f7d0df4f5cfdc01d28e10b0cfe32a..cc9804f91ff75baf77e4670ca4a591795bd86868 100644
--- a/src/sbbs3/scansubs.cpp
+++ b/src/sbbs3/scansubs.cpp
@@ -333,7 +333,7 @@ void sbbs_t::new_scan_ptr_cfg()
 			}
 			if(s==-1 || !s || s==quit_key())
 				break;
-			if(s==*text[AllKey]) {    /* The entire group */
+			if(s == all_key()) {    /* The entire group */
 				mnemonics(text[SetMsgPtrPrompt]);
 				SAFEPRINTF2(keys, "%s%c", text[DateLastKeys], quit_key());
 				s=getkeys(keys, 9999);
diff --git a/src/sbbs3/scfglib.h b/src/sbbs3/scfglib.h
index aa3e089d076cffa62b96ce91264c9a6159932d0b..dd7877c732512de5d92c3269de42d89c9ed9596e 100644
--- a/src/sbbs3/scfglib.h
+++ b/src/sbbs3/scfglib.h
@@ -52,7 +52,7 @@ DLLEXPORT void	free_chat_cfg(scfg_t* cfg);
 
 DLLEXPORT uint32_t aftou32(const char *str);      /* Converts flag string to uint32_t */
 DLLEXPORT char*	u32toaf(uint32_t t, char *str); /* Converts uint32_t to flag string */
-uint	attrstr(char *str);		/* Convert ATTR string into attribute int */
+uint	attrstr(const char *str);		/* Convert ATTR string into attribute int */
 
 int		getdirnum(scfg_t*, const char* code);
 int		getlibnum(scfg_t*, const char* code);
diff --git a/src/sbbs3/scfglib2.c b/src/sbbs3/scfglib2.c
index f4e5ad7345519059911b51a6d8b7c5a3025b6bcb..23f932be4468a37349d7ef463a6a59baa0cb899d 100644
--- a/src/sbbs3/scfglib2.c
+++ b/src/sbbs3/scfglib2.c
@@ -768,7 +768,7 @@ char *u32toaf(uint32_t l,char *str)
 /****************************************************************************/
 /* Returns the actual attribute code from a string of ATTR characters       */
 /****************************************************************************/
-uint attrstr(char *str)
+uint attrstr(const char *str)
 {
 	int atr;
 	ulong l=0;
diff --git a/src/sbbs3/text.h b/src/sbbs3/text.h
index acc7f93720f70c1b1642ca9701f732c84a2546a4..9afbfdfaa1158d6c718658c13ef09b6ef9aa9c30 100644
--- a/src/sbbs3/text.h
+++ b/src/sbbs3/text.h
@@ -4,7 +4,7 @@
 
 /****************************************************************************/
 /* Macros for elements of the array of pointers (text[]) to static text		*/
-/* Auto-generated from CTRL\TEXT.DAT										*/
+/* Auto-generated from ctrl/text.dat 										*/
 /****************************************************************************/
 
 #ifndef _TEXT_H
@@ -14,7 +14,7 @@ extern
 #ifdef __cplusplus
 "C"
 #endif
-const char* const text_id[]; 
+const char* const text_id[];
 
 enum {
 	 MsgSubj
@@ -156,8 +156,8 @@ enum {
 	,SubPtrLstFmt
 	,WhichOrAll
 	,RawMsgInputModeIsNow
-	,OFF
-	,ON
+	,Unused140 /* was OFF */
+	,Unused141 /* was ON */
 	,PagingUser
 	,SystemStatsHdr
 	,NodeStatsHdr
@@ -736,7 +736,7 @@ enum {
 	,NodeActionPrivateChat
 	,NodeActionPaging
 	,NodeActionRetrieving
-	,YNQP /* (Yes/No/Quit/Password chars) */
+	,Unused720 /* Used to be YNQP */
 	,ViewSignatureQ
 	,DeleteSignatureQ
 	,CreateEditSignatureQ
@@ -869,9 +869,9 @@ enum {
 	,DateLastKeys
 	,DirLibKeys
 	,SubGroupKeys
-	,AllKey
+	,Unused853
 	,All
-	,ListKey
+	,List
 	,InternetMailReceived
 	,InternetMailForwarded
 	,FidoNetMailReceived
@@ -882,6 +882,13 @@ enum {
 	,NewUserValEmailSubj
 	,InactivityAlert
 	,None
+	,Which
+	,Next
+	,Previous
+	,Quit
+	,Language
+	,LANG
+	,PasswordChar
 
 	,TOTAL_TEXT
 };
diff --git a/src/sbbs3/text_defaults.c b/src/sbbs3/text_defaults.c
index ea4f5cce5366a3e94e2e05402e22a5282e83a5ad..3d77bab8bd22e3707e94a4c74d6b69a8d6f1073d 100644
--- a/src/sbbs3/text_defaults.c
+++ b/src/sbbs3/text_defaults.c
@@ -73,7 +73,7 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x01\x62\x01\x68\x41\x75\x74\x6f\x20\x6d\x65\x73\x73\x61\x67\x65\x20\x62\x79\x3a\x20\x01\x63\x25\x73\x01\x62\x20\x6f\x6e\x20\x25"
 		"\x73\x01\x6e\x0d\x0a\x0d\x0a" // 042 AutoMsgBy
 	,"\x0d\x0a\x41\x75\x74\x6f\x20\x4d\x65\x73\x73\x61\x67\x65\x20\x2d\x20\x7e\x52\x65\x61\x64\x2c\x20\x7e\x57\x72\x69\x74\x65\x2c\x20"
-		"\x6f\x72\x20\x7e\x51\x75\x69\x74\x3a\x20" // 043 AutoMsg
+		"\x6f\x72\x20\x7e\x40\x51\x75\x69\x74\x40\x3a\x20" // 043 AutoMsg
 	,"\x01\x6e\x0d\x0a\x59\x6f\x75\x20\x63\x61\x6e\x27\x74\x20\x77\x72\x69\x74\x65\x20\x74\x6f\x20\x74\x68\x65\x20\x61\x75\x74\x6f\x2d"
 		"\x6d\x65\x73\x73\x61\x67\x65\x2e\x0d\x0a" // 044 R_AutoMsg
 	,"\x01\x6e\x0d\x0a\x59\x6f\x75\x20\x68\x61\x76\x65\x20\x6e\x6f\x20\x25\x73\x2e\x0d\x0a" // 045 NoMailWaiting
@@ -150,21 +150,22 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x01\x6c\x01\x5f\x01\x63\x01\x68\x47\x65\x6e\x65\x72\x61\x6c\x20\x54\x65\x78\x74\x20\x46\x69\x6c\x65\x20\x53\x65\x63\x74\x69\x6f"
 		"\x6e\x73\x3a\x0d\x0a\x0d\x0a" // 081 TextSectionLstHdr
 	,"\x01\x6e\x01\x63\x3c\x01\x68\x25\x64\x01\x6e\x01\x63\x3e\x20\x25\x73\x0d\x0a" // 082 TextSectionLstFmt
-	,"\x01\x5f\x0d\x0a\x01\x63\x57\x68\x69\x63\x68\x20\x6f\x72\x20\x01\x68\x7e\x51\x01\x6e\x01\x63\x75\x69\x74\x3a\x20\x01\x68" // 083 WhichTextSection
+	,"\x01\x5f\x0d\x0a\x01\x63\x40\x57\x68\x69\x63\x68\x40\x20\x6f\x72\x20\x01\x68\x7e\x51\x01\x6e\x01\x63\x75\x69\x74\x3a\x20\x01\x68"
+		"" // 083 WhichTextSection
 	,"\x01\x6c\x01\x5f\x01\x63\x01\x68\x25\x73\x20\x46\x69\x6c\x65\x73\x3a\x0d\x0a\x0d\x0a" // 084 TextFilesLstHdr
 	,"\x01\x63\x01\x68\x25\x33\x64\x3a\x20\x01\x6e\x01\x63\x25\x73" // 085 TextFilesLstFmt
-	,"\x0d\x0a\x57\x68\x69\x63\x68\x2c\x20\x7e\x41\x64\x64\x2c\x20\x7e\x52\x65\x6d\x6f\x76\x65\x2c\x20\x7e\x45\x64\x69\x74\x2c\x20\x6f"
-		"\x72\x20\x7e\x51\x75\x69\x74\x3a\x20" // 086 WhichTextFileSysop
-	,"\x01\x5f\x0d\x0a\x01\x6e\x01\x63\x57\x68\x69\x63\x68\x20\x6f\x72\x20\x01\x68\x7e\x51\x01\x6e\x01\x63\x75\x69\x74\x3a\x20\x01\x68"
-		"" // 087 WhichTextFile
+	,"\x0d\x0a\x40\x57\x68\x69\x63\x68\x40\x2c\x20\x7e\x41\x64\x64\x2c\x20\x7e\x52\x65\x6d\x6f\x76\x65\x2c\x20\x7e\x45\x64\x69\x74\x2c"
+		"\x20\x6f\x72\x20\x7e\x40\x51\x75\x69\x74\x40\x3a\x20" // 086 WhichTextFileSysop
+	,"\x01\x5f\x0d\x0a\x01\x6e\x01\x63\x40\x57\x68\x69\x63\x68\x40\x20\x6f\x72\x20\x01\x68\x7e\x51\x01\x6e\x01\x63\x75\x69\x74\x3a\x20"
+		"\x01\x68" // 087 WhichTextFile
 	,"\x01\x5f\x0d\x0a\x01\x79\x01\x68\x42\x65\x66\x6f\x72\x65\x20\x77\x68\x69\x63\x68\x20\x66\x69\x6c\x65\x20\x5b\x6c\x61\x73\x74\x5d"
 		"\x3a\x20\x01\x6e" // 088 AddTextFileBeforeWhich
 	,"\x0d\x0a\x50\x61\x74\x68\x20\x61\x6e\x64\x20\x66\x69\x6c\x65\x6e\x61\x6d\x65\x20\x28\x6e\x6f\x20\x70\x61\x74\x68\x20\x69\x6e\x64"
 		"\x69\x63\x61\x74\x65\x73\x20\x25\x73\x74\x65\x78\x74\x2f\x25\x73\x2f\x66\x69\x6c\x65\x6e\x61\x6d\x65\x29\x3a\x0d\x0a" // 089 AddTextFilePath
 	,"\x44\x65\x73\x63\x72\x69\x70\x74\x69\x6f\x6e\x3a\x0d\x0a" // 090 AddTextFileDesc
-	,"\x01\x5f\x0d\x0a\x01\x79\x01\x68\x52\x65\x6d\x6f\x76\x65\x20\x77\x68\x69\x63\x68\x3a\x20\x01\x6e" // 091 RemoveWhichTextFile
+	,"\x01\x5f\x0d\x0a\x01\x79\x01\x68\x52\x65\x6d\x6f\x76\x65\x20\x40\x57\x68\x69\x63\x68\x40\x3a\x20\x01\x6e" // 091 RemoveWhichTextFile
 	,"\x44\x65\x6c\x65\x74\x65\x20\x25\x73" // 092 DeleteTextFileQ
-	,"\x01\x5f\x0d\x0a\x01\x79\x01\x68\x45\x64\x69\x74\x20\x77\x68\x69\x63\x68\x3a\x20\x01\x6e" // 093 EditWhichTextFile
+	,"\x01\x5f\x0d\x0a\x01\x79\x01\x68\x45\x64\x69\x74\x20\x40\x57\x68\x69\x63\x68\x40\x3a\x20\x01\x6e" // 093 EditWhichTextFile
 	,"\x0d\x0a\x53\x65\x61\x72\x63\x68\x20\x61\x6c\x6c\x20\x67\x72\x6f\x75\x70\x73\x20\x66\x6f\x72\x20\x6e\x65\x77\x20\x6d\x65\x73\x73"
 		"\x61\x67\x65\x73" // 094 NScanAllGrpsQ
 	,"\x0d\x0a\x53\x65\x61\x72\x63\x68\x20\x61\x6c\x6c\x20\x67\x72\x6f\x75\x70\x73\x20\x66\x6f\x72\x20\x75\x6e\x2d\x72\x65\x61\x64\x20"
@@ -215,25 +216,25 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x01\x6e\x01\x67\x5b\x01\x68\x25\x75\x01\x6e\x01\x67\x5d\x20\x25\x2d\x34\x30\x73\x20\x25\x31\x32\x73\x20\x01\x68\x25\x34\x75\x0d"
 		"\x0a" // 128 GrpLstFmt
 	,"\x0d\x0a\x47\x72\x6f\x75\x70\x20\x74\x6f\x20\x63\x6f\x6e\x66\x69\x67\x75\x72\x65\x20\x6e\x65\x77\x20\x6d\x65\x73\x73\x61\x67\x65"
-		"\x20\x73\x63\x61\x6e\x20\x6f\x72\x20\x7e\x51\x75\x69\x74\x3a\x20" // 129 NScanCfgWhichGrp
+		"\x20\x73\x63\x61\x6e\x20\x6f\x72\x20\x7e\x40\x51\x75\x69\x74\x40\x3a\x20" // 129 NScanCfgWhichGrp
 	,"\x0d\x0a\x47\x72\x6f\x75\x70\x20\x74\x6f\x20\x63\x6f\x6e\x66\x69\x67\x75\x72\x65\x20\x79\x6f\x75\x72\x20\x6d\x65\x73\x73\x61\x67"
-		"\x65\x20\x73\x63\x61\x6e\x20\x6f\x72\x20\x7e\x51\x75\x69\x74\x3a\x20" // 130 SScanCfgWhichGrp
+		"\x65\x20\x73\x63\x61\x6e\x20\x6f\x72\x20\x7e\x40\x51\x75\x69\x74\x40\x3a\x20" // 130 SScanCfgWhichGrp
 	,"\x01\x6c\x01\x2d\x01\x67\x53\x75\x62\x2d\x62\x6f\x61\x72\x64\x73\x20\x6f\x66\x20\x01\x68\x25\x73\x3a\x0d\x0a\x0d\x0a\x01\x68" // 131 CfgSubLstHdr
 	,"\x01\x6e\x01\x67\x5b\x01\x68\x25\x64\x01\x6e\x01\x67\x5d\x20\x25\x2d\x34\x30\x2e\x34\x30\x73\x20\x20\x01\x68\x25\x73\x0d\x0a" // 132 CfgSubLstFmt
 	,"\x01\x6c\x01\x5f\x01\x67\x01\x68\x4d\x65\x73\x73\x61\x67\x65\x20\x47\x72\x6f\x75\x70\x73\x3a\x0d\x0a\x0d\x0a" // 133 CfgGrpLstHdr
 	,"\x01\x6e\x01\x67\x5b\x01\x68\x25\x64\x01\x6e\x01\x67\x5d\x20\x25\x73\x01\x68\x0d\x0a" // 134 CfgGrpLstFmt
 	,"\x0d\x0a\x53\x75\x62\x2d\x62\x6f\x61\x72\x64\x20\x74\x6f\x20\x74\x6f\x67\x67\x6c\x65\x20\x6e\x65\x77\x20\x6d\x65\x73\x73\x61\x67"
-		"\x65\x20\x73\x63\x61\x6e\x2c\x20\x7e\x41\x6c\x6c\x2c\x20\x6f\x72\x20\x7e\x51\x75\x69\x74\x3a\x20" // 135 NScanCfgWhichSub
+		"\x65\x20\x73\x63\x61\x6e\x2c\x20\x7e\x40\x41\x6c\x6c\x40\x2c\x20\x6f\x72\x20\x7e\x40\x51\x75\x69\x74\x40\x3a\x20" // 135 NScanCfgWhichSub
 	,"\x0d\x0a\x53\x75\x62\x2d\x62\x6f\x61\x72\x64\x20\x74\x6f\x20\x74\x6f\x67\x67\x6c\x65\x20\x79\x6f\x75\x72\x20\x6d\x65\x73\x73\x61"
-		"\x67\x65\x20\x73\x63\x61\x6e\x2c\x20\x7e\x41\x6c\x6c\x2c\x20\x6f\x72\x20\x7e\x51\x75\x69\x74\x3a\x20" // 136 SScanCfgWhichSub
+		"\x67\x65\x20\x73\x63\x61\x6e\x2c\x20\x7e\x40\x41\x6c\x6c\x40\x2c\x20\x6f\x72\x20\x7e\x40\x51\x75\x69\x74\x40\x3a\x20" // 136 SScanCfgWhichSub
 	,"\x01\x6e\x01\x67\x5b\x01\x68\x25\x64\x01\x6e\x01\x67\x5d\x20\x25\x2d\x34\x30\x2e\x34\x30\x73\x20\x20\x01\x68\x01\x63\x25\x73\x0d"
 		"\x0a" // 137 SubPtrLstFmt
-	,"\x0d\x0a\x53\x65\x74\x20\x6e\x65\x77\x2d\x73\x63\x61\x6e\x20\x70\x6f\x69\x6e\x74\x65\x72\x20\x66\x6f\x72\x20\x77\x68\x69\x63\x68"
-		"\x2c\x20\x7e\x41\x6c\x6c\x2c\x20\x6f\x72\x20\x7e\x51\x75\x69\x74\x3a\x20" // 138 WhichOrAll
+	,"\x0d\x0a\x53\x65\x74\x20\x6e\x65\x77\x2d\x73\x63\x61\x6e\x20\x70\x6f\x69\x6e\x74\x65\x72\x20\x66\x6f\x72\x20\x40\x57\x68\x69\x63"
+		"\x68\x40\x2c\x20\x7e\x40\x41\x6c\x6c\x40\x2c\x20\x6f\x72\x20\x7e\x40\x51\x75\x69\x74\x40\x3a\x20" // 138 WhichOrAll
 	,"\x0d\x0a\x52\x61\x77\x20\x49\x6e\x70\x75\x74\x2f\x4f\x75\x74\x70\x75\x74\x20\x4d\x6f\x64\x65\x20\x69\x73\x20\x6e\x6f\x77\x3a\x20"
 		"\x01\x68" // 139 RawMsgInputModeIsNow
-	,"\x4f\x46\x46" // 140 OFF
-	,"\x4f\x4e" // 141 ON
+	,"\x4f\x46\x46" // 140 Unused140 /* was OFF */
+	,"\x4f\x4e" // 141 Unused141 /* was ON */
 	,"\x0d\x0a\x01\x6e\x01\x6d\x50\x61\x67\x69\x6e\x67\x20\x01\x68\x25\x73\x20\x23\x25\x75\x01\x6e\x01\x6d\x20\x66\x6f\x72\x20\x70\x72"
 		"\x69\x76\x61\x74\x65\x20\x63\x68\x61\x74\x0d\x0a" // 142 PagingUser
 	,"\x0d\x0a\x01\x2d\x01\x67\x53\x79\x73\x74\x65\x6d\x20\x53\x74\x61\x74\x69\x73\x74\x69\x63\x73\x3a\x0d\x0a\x0d\x0a\x01\x6e" // 143 SystemStatsHdr
@@ -369,8 +370,8 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x0d\x0a\x01\x2d\x01\x67\x45\x6e\x74\x65\x72\x20\x61\x20\x64\x65\x73\x63\x72\x69\x70\x74\x69\x6f\x6e\x20\x6e\x6f\x77\x2e\x0d\x0a"
 		"\x3a\x20" // 225 EnterDescNow
 	,"\x4e\x6f\x20\x64\x65\x73\x63\x72\x69\x70\x74\x69\x6f\x6e\x20\x67\x69\x76\x65\x6e\x2e" // 226 NoDescription
-	,"\x0d\x0a\x50\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x6f\x72\x20\x7e\x51\x75\x69\x74\x3a\x20" // 227 ProtocolOrQuit
-	,"\x0d\x0a\x50\x72\x6f\x74\x6f\x63\x6f\x6c\x2c\x20\x7e\x42\x61\x74\x63\x68\x20\x6f\x72\x20\x7e\x51\x75\x69\x74\x3a\x20" // 228 ProtocolBatchOrQuit
+	,"\x0d\x0a\x50\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x6f\x72\x20\x7e\x40\x51\x75\x69\x74\x40\x3a\x20" // 227 ProtocolOrQuit
+	,"\x0d\x0a\x50\x72\x6f\x74\x6f\x63\x6f\x6c\x2c\x20\x7e\x42\x61\x74\x63\x68\x20\x6f\x72\x20\x7e\x40\x51\x75\x69\x74\x40\x3a\x20" // 228 ProtocolBatchOrQuit
 	,"\x0d\x0a\x07\x01\x72\x01\x68\x01\x69\x42\x61\x74\x63\x68\x20\x75\x70\x6c\x6f\x61\x64\x20\x71\x75\x65\x75\x65\x20\x69\x73\x20\x66"
 		"\x75\x6c\x6c\x2e\x01\x6e\x0d\x0a" // 229 BatchUlQueueIsFull
 	,"\x0d\x0a\x01\x6e\x01\x6d\x01\x68\x25\x73\x20\x01\x6e\x01\x6d\x61\x64\x64\x65\x64\x20\x74\x6f\x20\x62\x61\x74\x63\x68\x20\x75\x70"
@@ -384,9 +385,10 @@ const char * const text_defaults[TOTAL_TEXT]={
 		"\x64\x2c\x20\x01\x77\x7e\x45\x01\x79\x78\x74\x65\x6e\x64\x65\x64\x20\x69\x6e\x66\x6f\x2c\x20\x01\x77\x7e\x56\x01\x79\x69\x65\x77"
 		"\x20\x66\x69\x6c\x65\x2c\x20\x01\x77\x7e\x51\x01\x79\x75\x69\x74\x2c\x20\x01\x77\x7e\x50\x01\x79\x72\x65\x76\x20\x6f\x72\x20\x5b"
 		"\x7e\x4e\x65\x78\x74\x5d\x3a\x20\x01\x77" // 232 FileInfoPrompt
-	,"\x0d\x0a\x7e\x51\x75\x69\x74\x20\x6f\x72\x20\x5b\x7e\x4e\x65\x78\x74\x5d\x3a\x20" // 233 QuitOrNext
+	,"\x0d\x0a\x7e\x40\x51\x75\x69\x74\x40\x20\x6f\x72\x20\x5b\x7e\x4e\x65\x78\x74\x5d\x3a\x20" // 233 QuitOrNext
 	,"\x7e\x52\x65\x6d\x6f\x76\x65\x2c\x20\x7e\x4d\x6f\x76\x65\x2c\x20\x7e\x45\x64\x69\x74\x2c\x20\x7e\x44\x65\x73\x63\x2c\x20\x7e\x56"
-		"\x69\x65\x77\x2c\x20\x7e\x51\x75\x69\x74\x2c\x20\x7e\x50\x72\x65\x76\x20\x6f\x72\x20\x5b\x7e\x4e\x65\x78\x74\x5d\x3a\x20" // 234 RExemptRemoveFilePrompt
+		"\x69\x65\x77\x2c\x20\x7e\x40\x51\x75\x69\x74\x40\x2c\x20\x7e\x50\x72\x65\x76\x20\x6f\x72\x20\x5b\x7e\x4e\x65\x78\x74\x5d\x3a\x20"
+		"" // 234 RExemptRemoveFilePrompt
 	,"\x01\x6e\x28\x25\x64\x29\x20\x25\x73\x0d\x0a" // 235 MoveToLibLstFmt
 	,"\x01\x5f\x0d\x0a\x01\x79\x01\x68\x4c\x69\x62\x72\x61\x72\x79\x20\x5b\x25\x64\x5d\x3a\x20\x01\x6e" // 236 MoveToLibPrompt
 	,"\x01\x6e\x28\x25\x64\x29\x20\x25\x73\x0d\x0a" // 237 MoveToDirLstFmt
@@ -394,10 +396,10 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x25\x73\x20\x6d\x6f\x76\x65\x64\x20\x74\x6f\x20\x25\x73\x20\x25\x73\x2e\x0d\x0a" // 239 MovedFile
 	,"\x0d\x0a\x43\x6c\x6f\x73\x65\x20\x66\x69\x6c\x65\x20\x72\x65\x63\x6f\x72\x64" // 240 CloseFileRecordQ
 	,"\x7e\x52\x65\x6d\x6f\x76\x65\x2c\x20\x7e\x43\x72\x65\x64\x69\x74\x73\x2c\x20\x7e\x46\x69\x6c\x65\x20\x6f\x6e\x6c\x79\x2c\x20\x7e"
-		"\x4d\x6f\x76\x65\x2c\x20\x7e\x45\x64\x69\x74\x2c\x20\x7e\x44\x65\x73\x63\x2c\x20\x7e\x56\x69\x65\x77\x2c\x20\x7e\x51\x75\x69\x74"
-		"\x2c\x20\x7e\x50\x72\x65\x76\x20\x6f\x72\x20\x5b\x7e\x4e\x65\x78\x74\x5d\x3a\x20" // 241 SysopRemoveFilePrompt
-	,"\x7e\x52\x65\x6d\x6f\x76\x65\x2c\x20\x7e\x45\x64\x69\x74\x2c\x20\x7e\x44\x65\x73\x63\x2c\x20\x7e\x56\x69\x65\x77\x2c\x20\x7e\x51"
-		"\x75\x69\x74\x2c\x20\x7e\x50\x72\x65\x76\x20\x6f\x72\x20\x5b\x7e\x4e\x65\x78\x74\x5d\x3a\x20" // 242 UserRemoveFilePrompt
+		"\x4d\x6f\x76\x65\x2c\x20\x7e\x45\x64\x69\x74\x2c\x20\x7e\x44\x65\x73\x63\x2c\x20\x7e\x56\x69\x65\x77\x2c\x20\x7e\x40\x51\x75\x69"
+		"\x74\x40\x2c\x20\x7e\x50\x72\x65\x76\x20\x6f\x72\x20\x5b\x7e\x4e\x65\x78\x74\x5d\x3a\x20" // 241 SysopRemoveFilePrompt
+	,"\x7e\x52\x65\x6d\x6f\x76\x65\x2c\x20\x7e\x45\x64\x69\x74\x2c\x20\x7e\x44\x65\x73\x63\x2c\x20\x7e\x56\x69\x65\x77\x2c\x20\x7e\x40"
+		"\x51\x75\x69\x74\x40\x2c\x20\x7e\x50\x72\x65\x76\x20\x6f\x72\x20\x5b\x7e\x4e\x65\x78\x74\x5d\x3a\x20" // 242 UserRemoveFilePrompt
 	,"\x0d\x0a\x01\x6e\x01\x72\x01\x68\x46\x69\x6c\x65\x20\x64\x6f\x65\x73\x20\x6e\x6f\x74\x20\x65\x78\x69\x73\x74\x3a\x20\x01\x63\x25"
 		"\x73\x01\x6e\x0d\x0a" // 243 FileDoesNotExist
 	,"\x07\x0d\x0a\x01\x72\x01\x68\x01\x69\x43\x6f\x75\x6c\x64\x6e\x27\x74\x20\x72\x65\x6d\x6f\x76\x65\x20\x27\x25\x73\x27\x2e\x01\x6e"
@@ -426,8 +428,8 @@ const char * const text_defaults[TOTAL_TEXT]={
 		"\x0d\x0a" // 262 NotEnoughCredits
 	,"\x0d\x0a\x01\x77\x01\x68\x4e\x6f\x74\x20\x65\x6e\x6f\x75\x67\x68\x20\x74\x69\x6d\x65\x20\x6c\x65\x66\x74\x20\x74\x6f\x20\x74\x72"
 		"\x61\x6e\x73\x66\x65\x72\x2e\x0d\x0a" // 263 NotEnoughTimeToDl
-	,"\x0d\x0a\x50\x72\x6f\x74\x6f\x63\x6f\x6c\x2c\x20\x7e\x42\x61\x74\x63\x68\x2c\x20\x7e\x51\x75\x69\x74\x2c\x20\x6f\x72\x20\x5b\x7e"
-		"\x4e\x65\x78\x74\x5d\x3a\x20" // 264 ProtocolBatchQuitOrNext
+	,"\x0d\x0a\x50\x72\x6f\x74\x6f\x63\x6f\x6c\x2c\x20\x7e\x42\x61\x74\x63\x68\x2c\x20\x7e\x40\x51\x75\x69\x74\x40\x2c\x20\x6f\x72\x20"
+		"\x5b\x7e\x4e\x65\x78\x74\x5d\x3a\x20" // 264 ProtocolBatchQuitOrNext
 	,"\x0d\x0a\x42\x75\x6c\x6b\x20\x55\x70\x6c\x6f\x61\x64\x20\x25\x73\x20\x25\x73\x20\x44\x69\x72\x65\x63\x74\x6f\x72\x79\x0d\x0a\x28"
 		"\x45\x6e\x74\x65\x72\x20\x27\x2d\x27\x20\x66\x6f\x72\x20\x64\x65\x73\x63\x72\x69\x70\x74\x69\x6f\x6e\x20\x74\x6f\x20\x73\x6b\x69"
 		"\x70\x20\x66\x69\x6c\x65\x29\x3a\x0d\x0a" // 265 BulkUpload
@@ -470,7 +472,7 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x0d\x0a\x55\x6e\x65\x78\x74\x72\x61\x63\x74\x61\x62\x6c\x65\x20\x66\x69\x6c\x65\x20\x74\x79\x70\x65\x2e\x0d\x0a" // 289 UnextractableFile
 	,"\x0d\x0a\x46\x69\x6c\x65\x20\x6e\x6f\x74\x20\x66\x6f\x75\x6e\x64\x2e\x0d\x0a" // 290 FileNotFound
 	,"\x0d\x0a\x7e\x45\x78\x74\x72\x61\x63\x74\x20\x66\x69\x6c\x65\x28\x73\x29\x2c\x20\x7e\x56\x69\x65\x77\x20\x61\x72\x63\x68\x69\x76"
-		"\x65\x2c\x20\x6f\x72\x20\x7e\x51\x75\x69\x74\x3a\x20" // 291 ExtractFilesPrompt
+		"\x65\x2c\x20\x6f\x72\x20\x7e\x40\x51\x75\x69\x74\x40\x3a\x20" // 291 ExtractFilesPrompt
 	,"\x01\x5f\x01\x3f\x01\x79\x01\x68\x54\x65\x6d\x70\x20\x44\x69\x72\x65\x63\x74\x6f\x72\x79\x3a\x20\x01\x6e" // 292 TempDirPrompt
 	,"\x01\x6e\x0d\x0a\x25\x73\x20\x6e\x6f\x74\x20\x63\x72\x65\x61\x74\x65\x64\x20\x79\x65\x74\x2e\x0d\x0a\x0d\x0a\x55\x73\x65\x20\x74"
 		"\x68\x65\x20\x01\x68\x41\x01\x6e\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x20\x74\x6f\x20\x63\x72\x65\x61\x74\x65\x20\x69\x74\x2e\x0d\x0a"
@@ -636,7 +638,8 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x01\x68\xc4\xc4\xc4\xc4\xc5\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4"
 		"\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\x20" // 382 XtrnProgLstUnderline
 	,"\x01\x68\x01\x63\x25\x33\x75\x20\xb3\x20\x01\x6e\x01\x63\x25\x2d\x33\x32\x2e\x33\x32\x73\x01\x68\x20" // 383 XtrnProgLstFmt
-	,"\x0d\x0a\x01\x2d\x01\x63\x57\x68\x69\x63\x68\x20\x6f\x72\x20\x01\x68\x7e\x51\x01\x6e\x01\x63\x75\x69\x74\x3a\x20\x01\x68" // 384 WhichXtrnProg
+	,"\x0d\x0a\x01\x2d\x01\x63\x40\x57\x68\x69\x63\x68\x40\x20\x6f\x72\x20\x01\x68\x7e\x51\x01\x6e\x01\x63\x75\x69\x74\x3a\x20\x01\x68"
+		"" // 384 WhichXtrnProg
 	,"\x0d\x0a\x25\x73\x20\x69\x73\x20\x63\x75\x72\x72\x65\x6e\x74\x6c\x79\x20\x72\x75\x6e\x6e\x69\x6e\x67\x20\x25\x73\x20\x6f\x6e\x20"
 		"\x6e\x6f\x64\x65\x20\x25\x64\x2e\x0d\x0a\x0d\x0a\x54\x72\x79\x20\x61\x67\x61\x69\x6e\x20\x6c\x61\x74\x65\x72\x2e\x0d\x0a\x0d\x0a"
 		"" // 385 UserRunningXtrn
@@ -817,7 +820,8 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x5a\x01\x6e\x01\x62\x5d\x20\x01\x68\x44\x65\x66\x61\x75\x6c\x74\x20\x44\x6f\x77\x6e\x6c\x6f"
 		"\x61\x64\x20\x50\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x20\x20\x20\x01\x6e\x01\x62\x01\x5c\x3a\x20\x01\x63\x25\x73\x20\x01\x62\x25\x73"
 		"\x0d\x0a" // 493 UserDefaultsProtocol
-	,"\x0d\x0a\x01\x6e\x01\x68\x01\x62\x57\x68\x69\x63\x68\x20\x6f\x72\x20\x5b\x01\x77\x51\x01\x62\x5d\x75\x69\x74\x3a\x20\x01\x63" // 494 UserDefaultsWhich
+	,"\x0d\x0a\x01\x6e\x01\x68\x01\x62\x40\x57\x68\x69\x63\x68\x40\x20\x6f\x72\x20\x5b\x01\x77\x51\x01\x62\x5d\x20\x74\x6f\x20\x40\x51"
+		"\x75\x69\x74\x40\x3a\x20\x01\x63" // 494 UserDefaultsWhich
 	,"\x4f\x6e" // 495 On
 	,"\x4f\x66\x66" // 496 Off
 	,"\x01\x5f\x01\x62\x01\x68\x5b\x01\x63\x40\x43\x48\x45\x43\x4b\x4d\x41\x52\x4b\x40\x01\x62\x5d\x20\x01\x79\x54\x65\x72\x6d\x69\x6e"
@@ -830,7 +834,7 @@ const char * const text_defaults[TOTAL_TEXT]={
 		"\x64\x6f\x6d\x61\x69\x6e\x29\x0d\x0a\x20\x3a\x20" // 500 EnterNetMailAddress
 	,"\x01\x6e\x01\x6c\x01\x67\x53\x65\x6c\x65\x63\x74\x20\x01\x68\x25\x73\x01\x6e\x01\x67\x3a\x0d\x0a\x0d\x0a" // 501 SelectItemHdr
 	,"\x01\x67\x01\x68\x25\x33\x64\x3a\x20\x01\x6e\x01\x67\x25\x73\x0d\x0a" // 502 SelectItemFmt
-	,"\x0d\x0a\x57\x68\x69\x63\x68\x2c\x20\x7e\x51\x75\x69\x74\x20\x6f\x72\x20\x5b\x25\x75\x5d\x3a\x20" // 503 SelectItemWhich
+	,"\x0d\x0a\x40\x57\x68\x69\x63\x68\x40\x2c\x20\x7e\x40\x51\x75\x69\x74\x40\x20\x6f\x72\x20\x5b\x25\x75\x5d\x3a\x20" // 503 SelectItemWhich
 	,"\x01\x5f\x01\x77\x01\x68\x0d\x0a\x0d\x0a\x25\x73\x20\x69\x73\x20\x68\x65\x72\x65\x2e\x2e\x2e\x0d\x0a\x0d\x0a\x01\x6e" // 504 SysopIsHere
 	,"\x0d\x0a\x01\x5f\x01\x77\x01\x68\x45\x6e\x64\x20\x6f\x66\x20\x63\x68\x61\x74\x2e\x0d\x0a\x0d\x0a\x01\x6e" // 505 EndOfChat
 	,"\x0d\x0a\x01\x5f\x01\x79\x01\x68\x43\x68\x61\x74\x3a\x20\x01\x6e" // 506 ChatPrompt
@@ -1041,9 +1045,9 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x52\x65\x6d\x6f\x76\x65\x20\x74\x68\x69\x73\x20\x73\x75\x62\x2d\x62\x6f\x61\x72\x64\x20\x66\x72\x6f\x6d\x20\x79\x6f\x75\x72\x20"
 		"\x6e\x65\x77\x2d\x73\x63\x61\x6e\x20\x6c\x69\x73\x74" // 620 RemoveFromNewScanQ
 	,"\x0d\x0a\x7e\x53\x75\x62\x2d\x62\x6f\x61\x72\x64\x3a\x20\x40\x53\x55\x42\x40\x2c\x20\x7e\x47\x72\x6f\x75\x70\x3a\x20\x40\x47\x52"
-		"\x50\x40\x2c\x20\x6f\x72\x20\x7e\x41\x6c\x6c\x3a\x20" // 621 SubGroupOrAll
+		"\x50\x40\x2c\x20\x6f\x72\x20\x7e\x40\x41\x6c\x6c\x40\x3a\x20" // 621 SubGroupOrAll
 	,"\x0d\x0a\x7e\x44\x69\x72\x65\x63\x74\x6f\x72\x79\x3a\x20\x40\x44\x49\x52\x40\x2c\x20\x7e\x4c\x69\x62\x72\x61\x72\x79\x3a\x20\x40"
-		"\x4c\x49\x42\x40\x2c\x20\x6f\x72\x20\x7e\x41\x6c\x6c\x3a\x20" // 622 DirLibOrAll
+		"\x4c\x49\x42\x40\x2c\x20\x6f\x72\x20\x7e\x40\x41\x6c\x6c\x40\x3a\x20" // 622 DirLibOrAll
 	,"\x0d\x0a\x01\x5f\x01\x79\x01\x68\x45\x6e\x74\x65\x72\x20\x70\x61\x74\x68\x3a\x20" // 623 EnterPath
 	,"\x01\x3f\x44\x69\x73\x70\x6c\x61\x79\x20\x65\x78\x74\x65\x6e\x64\x65\x64\x20\x66\x69\x6c\x65\x20\x69\x6e\x66\x6f\x72\x6d\x61\x74"
 		"\x69\x6f\x6e" // 624 DisplayExtendedFileInfoQ
@@ -1092,10 +1096,10 @@ const char * const text_defaults[TOTAL_TEXT]={
 		"\x20\x25\x73\x2e\x0d\x0a" // 650 UserReadYourMail
 	,"\x01\x5f\x01\x77\x01\x68\x4e\x6f\x64\x65\x20\x25\x32\x64\x3a\x20\x01\x67\x25\x73\x01\x6e\x01\x67\x20\x72\x65\x61\x64\x20\x79\x6f"
 		"\x75\x72\x20\x45\x2d\x6d\x61\x69\x6c\x2e\x0d\x0a" // 651 UserReadYourMailNodeMsg
-	,"\x0d\x0a\x57\x68\x69\x63\x68\x2c\x20\x7e\x51\x75\x69\x74\x2c\x20\x6f\x72\x20\x5b\x25\x75\x5d\x3a\x20" // 652 JoinWhichGrp
-	,"\x0d\x0a\x57\x68\x69\x63\x68\x2c\x20\x7e\x51\x75\x69\x74\x2c\x20\x6f\x72\x20\x5b\x25\x75\x5d\x3a\x20" // 653 JoinWhichSub
-	,"\x0d\x0a\x57\x68\x69\x63\x68\x2c\x20\x7e\x51\x75\x69\x74\x2c\x20\x6f\x72\x20\x5b\x25\x75\x5d\x3a\x20" // 654 JoinWhichLib
-	,"\x0d\x0a\x57\x68\x69\x63\x68\x2c\x20\x7e\x51\x75\x69\x74\x2c\x20\x6f\x72\x20\x5b\x25\x75\x5d\x3a\x20" // 655 JoinWhichDir
+	,"\x0d\x0a\x40\x57\x68\x69\x63\x68\x40\x2c\x20\x7e\x40\x51\x75\x69\x74\x40\x2c\x20\x6f\x72\x20\x5b\x25\x75\x5d\x3a\x20" // 652 JoinWhichGrp
+	,"\x0d\x0a\x40\x57\x68\x69\x63\x68\x40\x2c\x20\x7e\x40\x51\x75\x69\x74\x40\x2c\x20\x6f\x72\x20\x5b\x25\x75\x5d\x3a\x20" // 653 JoinWhichSub
+	,"\x0d\x0a\x40\x57\x68\x69\x63\x68\x40\x2c\x20\x7e\x40\x51\x75\x69\x74\x40\x2c\x20\x6f\x72\x20\x5b\x25\x75\x5d\x3a\x20" // 654 JoinWhichLib
+	,"\x0d\x0a\x40\x57\x68\x69\x63\x68\x40\x2c\x20\x7e\x40\x51\x75\x69\x74\x40\x2c\x20\x6f\x72\x20\x5b\x25\x75\x5d\x3a\x20" // 655 JoinWhichDir
 	,"\x01\x6c\x01\x2d\x01\x67\x44\x69\x72\x65\x63\x74\x6f\x72\x69\x65\x73\x20\x6f\x66\x20\x01\x68\x25\x73\x3a\x0d\x0a\x0d\x0a\x01\x68"
 		"" // 656 CfgDirLstHdr
 	,"\x20\x01\x6e\x01\x67\x28\x01\x68\x25\x64\x01\x6e\x01\x67\x29\x20\x25\x73\x01\x68\x0d\x0a" // 657 CfgDirLstFmt
@@ -1176,7 +1180,7 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"" // 717 NodeActionPrivateChat
 	,"" // 718 NodeActionPaging
 	,"" // 719 NodeActionRetrieving
-	,"\x59\x4e\x51\x2a" // 720 YNQP /* (Yes/No/Quit/Password chars) */
+	,"\x59\x4e\x51\x2a" // 720 Unused720 /* Used to be YNQP */
 	,"\x56\x69\x65\x77\x20\x73\x69\x67\x6e\x61\x74\x75\x72\x65" // 721 ViewSignatureQ
 	,"\x44\x65\x6c\x65\x74\x65\x20\x73\x69\x67\x6e\x61\x74\x75\x72\x65" // 722 DeleteSignatureQ
 	,"\x43\x72\x65\x61\x74\x65\x2f\x45\x64\x69\x74\x20\x73\x69\x67\x6e\x61\x74\x75\x72\x65" // 723 CreateEditSignatureQ
@@ -1230,7 +1234,8 @@ const char * const text_defaults[TOTAL_TEXT]={
 		"\x65\x2f\x52\x65\x70\x6c\x79\x20\x49\x44\x73\x20\x20\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a" // 754 QWKSettingsMsgID
 	,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x58\x01\x6e\x01\x62\x5d\x20\x01\x68\x45\x78\x74\x65\x6e\x64\x65\x64\x20\x28\x51\x57\x4b\x45"
 		"\x29\x20\x50\x61\x63\x6b\x65\x74\x20\x46\x6f\x72\x6d\x61\x74\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a" // 755 QWKSettingsExtended
-	,"\x0d\x0a\x01\x6e\x01\x68\x01\x62\x57\x68\x69\x63\x68\x20\x6f\x72\x20\x5b\x01\x77\x51\x01\x62\x5d\x75\x69\x74\x3a\x20\x01\x63" // 756 QWKSettingsWhich
+	,"\x0d\x0a\x01\x6e\x01\x68\x01\x62\x40\x57\x68\x69\x63\x68\x40\x20\x6f\x72\x20\x5b\x01\x77\x51\x01\x62\x5d\x75\x69\x74\x3a\x20\x01"
+		"\x63" // 756 QWKSettingsWhich
 	,"\x01\x6e\x0d\x0a\x53\x6f\x72\x72\x79\x2c\x20\x79\x6f\x75\x20\x63\x61\x6e\x27\x74\x20\x65\x64\x69\x74\x20\x74\x68\x69\x73\x20\x6d"
 		"\x65\x73\x73\x61\x67\x65\x2e\x0d\x0a" // 757 CantEditMsg
 	,"\x01\x6e\x0d\x0a\x53\x6f\x72\x72\x79\x2c\x20\x79\x6f\x75\x20\x63\x61\x6e\x27\x74\x20\x64\x65\x6c\x65\x74\x65\x20\x6d\x65\x73\x73"
@@ -1293,7 +1298,7 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x56\x01\x6e\x01\x62\x5d\x20\x01\x68\x49\x6e\x63\x6c\x75\x64\x65\x20\x56\x4f\x54\x49\x4e\x47"
 		"\x2e\x44\x41\x54\x20\x46\x69\x6c\x65\x20\x20\x20\x20\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a" // 782 QWKSettingsVoting
 	,"\x0d\x0a\x56\x6f\x74\x65\x20\x66\x6f\x72\x20\x6d\x65\x73\x73\x61\x67\x65\x3a\x20\x7e\x55\x70\x2c\x20\x7e\x44\x6f\x77\x6e\x2c\x20"
-		"\x6f\x72\x20\x7e\x51\x75\x69\x74\x3a\x20" // 783 VoteMsgUpDownOrQuit
+		"\x6f\x72\x20\x7e\x40\x51\x75\x69\x74\x40\x3a\x20" // 783 VoteMsgUpDownOrQuit
 	,"\x0d\x0a\xb3\x20\x01\x62\x4d\x73\x67\x20\x01\x6e\x01\x62\x3a\x20\x01\x68\x01\x63\x56\x6f\x74\x65\x64\x20\x55\x70\x20\x25\x75\x20"
 		"\x74\x69\x6d\x65\x73\x25\x73\x20\x61\x6e\x64\x20\x44\x6f\x77\x6e\x20\x25\x75\x20\x74\x69\x6d\x65\x73\x25\x73\x20\x28\x53\x63\x6f"
 		"\x72\x65\x3a\x20\x25\x64\x29" // 784 MsgVotes
@@ -1310,8 +1315,8 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x20\xfb" // 790 PollAnswerChecked
 	,"\x01\x6e\x01\x6c\x01\x67\x42\x61\x6c\x6c\x6f\x74\x20\x66\x6f\x72\x20\x01\x68\x25\x73\x0d\x0a\x0d\x0a" // 791 BallotHdr
 	,"\x01\x6e\x01\x63\x01\x68\x25\x32\x75\x01\x6e\x01\x63\x3a\x20\x25\x2d\x2a\x2e\x2a\x73\x20\x01\x68\x25\x73\x0d\x0a" // 792 BallotAnswerFmt
-	,"\x0d\x0a\x54\x6f\x67\x67\x6c\x65\x20\x77\x68\x69\x63\x68\x20\x76\x6f\x74\x65\x20\x28\x75\x70\x20\x74\x6f\x20\x25\x75\x29\x2c\x20"
-		"\x7e\x51\x75\x69\x74\x20\x6f\x72\x20\x5b\x43\x61\x73\x74\x5d\x3a\x20" // 793 BallotVoteWhich
+	,"\x0d\x0a\x54\x6f\x67\x67\x6c\x65\x20\x40\x57\x68\x69\x63\x68\x40\x20\x76\x6f\x74\x65\x20\x28\x75\x70\x20\x74\x6f\x20\x25\x75\x29"
+		"\x2c\x20\x7e\x40\x51\x75\x69\x74\x40\x20\x6f\x72\x20\x5b\x43\x61\x73\x74\x5d\x3a\x20" // 793 BallotVoteWhich
 	,"\x4f\x6e\x6c\x79" // 794 Only
 	,"\x01\x6e\x01\x68\x01\x63\x0d\x0a\x53\x50\x41\x4d\x20\x56\x69\x73\x69\x62\x69\x6c\x69\x74\x79\x20\x69\x73\x20\x6e\x6f\x77\x3a\x20"
 		"\x01\x77" // 795 SPAMVisibilityIsNow
@@ -1390,14 +1395,14 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x4d\x65\x73\x73\x61\x67\x65\x73\x20\x74\x6f\x20\x79\x6f\x75\x20\x6f\x6e\x6c\x79" // 847 MsgsToYouOnlyQ
 	,"\x54\x6f\x20\x59\x6f\x75\x20\x4f\x6e\x6c\x79" // 848 ToYouOnly
 	,"\x0d\x0a\x45\x6e\x74\x65\x72\x20\x6e\x75\x6d\x62\x65\x72\x20\x6f\x66\x20\x6d\x65\x73\x73\x61\x67\x65\x73\x20\x66\x72\x6f\x6d\x20"
-		"\x65\x6e\x64\x2c\x20\x7e\x44\x61\x74\x65\x2c\x20\x7e\x51\x75\x69\x74\x2c\x20\x6f\x72\x20\x5b\x4c\x61\x73\x74\x20\x4d\x65\x73\x73"
-		"\x61\x67\x65\x5d\x3a\x20" // 849 SetMsgPtrPrompt
+		"\x65\x6e\x64\x2c\x20\x7e\x44\x61\x74\x65\x2c\x20\x7e\x40\x51\x75\x69\x74\x40\x2c\x20\x6f\x72\x20\x5b\x4c\x61\x73\x74\x20\x4d\x65"
+		"\x73\x73\x61\x67\x65\x5d\x3a\x20" // 849 SetMsgPtrPrompt
 	,"\x44\x4c" // 850 DateLastKeys
 	,"\x44\x4c" // 851 DirLibKeys
 	,"\x53\x47" // 852 SubGroupKeys
-	,"\x41" // 853 AllKey
+	,"\x41" // 853 Unused853
 	,"\x41\x6c\x6c" // 854 All
-	,"\x4c" // 855 ListKey
+	,"\x4c\x69\x73\x74" // 855 List
 	,"\x25\x2e\x30\x73\x01\x6e\x01\x6d\x4e\x65\x77\x20\x65\x2d\x6d\x61\x69\x6c\x20\x66\x72\x6f\x6d\x20\x01\x68\x25\x73\x20\x01\x6e\x3c"
 		"\x01\x68\x25\x73\x01\x6e\x3e\x0d\x0a" // 856 InternetMailReceived
 	,"\x01\x6e\x01\x6d\x61\x6e\x64\x20\x69\x74\x20\x77\x61\x73\x20\x61\x75\x74\x6f\x6d\x61\x74\x69\x63\x61\x6c\x6c\x79\x20\x66\x6f\x72"
@@ -1413,4 +1418,11 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x4e\x65\x77\x20\x55\x73\x65\x72\x20\x56\x61\x6c\x69\x64\x61\x74\x69\x6f\x6e" // 863 NewUserValEmailSubj
 	,"\x07\x07\x07" // 864 InactivityAlert
 	,"\x4e\x6f\x6e\x65" // 865 None
+	,"\x57\x68\x69\x63\x68" // 866 Which
+	,"\x4e\x65\x78\x74" // 867 Next
+	,"\x50\x72\x65\x76" // 868 Previous
+	,"\x51\x75\x69\x74" // 869 Quit
+	,"\x4c\x61\x6e\x67\x75\x61\x67\x65" // 870 Language
+	,"\x45\x6e\x67\x6c\x69\x73\x68" // 871 LANG
+	,"\x2a" // 872 PasswordChar
 };
diff --git a/src/sbbs3/text_id.c b/src/sbbs3/text_id.c
index a0d718ff077863b58ad3c9ac97f8e6b679786a9f..bd0748d20f26c977dd6d195110630ba051d6b788 100644
--- a/src/sbbs3/text_id.c
+++ b/src/sbbs3/text_id.c
@@ -140,8 +140,8 @@ const char* const text_id[]={
 	,"SubPtrLstFmt"
 	,"WhichOrAll"
 	,"RawMsgInputModeIsNow"
-	,"OFF"
-	,"ON"
+	,"Unused140 /* was OFF */"
+	,"Unused141 /* was ON */"
 	,"PagingUser"
 	,"SystemStatsHdr"
 	,"NodeStatsHdr"
@@ -720,7 +720,7 @@ const char* const text_id[]={
 	,"NodeActionPrivateChat"
 	,"NodeActionPaging"
 	,"NodeActionRetrieving"
-	,"YNQP /* (Yes/No/Quit/Password chars) */"
+	,"Unused720 /* Used to be YNQP */"
 	,"ViewSignatureQ"
 	,"DeleteSignatureQ"
 	,"CreateEditSignatureQ"
@@ -853,9 +853,9 @@ const char* const text_id[]={
 	,"DateLastKeys"
 	,"DirLibKeys"
 	,"SubGroupKeys"
-	,"AllKey"
+	,"Unused853"
 	,"All"
-	,"ListKey"
+	,"List"
 	,"InternetMailReceived"
 	,"InternetMailForwarded"
 	,"FidoNetMailReceived"
@@ -866,4 +866,11 @@ const char* const text_id[]={
 	,"NewUserValEmailSubj"
 	,"InactivityAlert"
 	,"None"
+	,"Which"
+	,"Next"
+	,"Previous"
+	,"Quit"
+	,"Language"
+	,"LANG"
+	,"PasswordChar"
 };