diff --git a/ctrl/SlyEdit.cfg b/ctrl/SlyEdit.cfg
index eebe9a4bf0df318f584c01e86c026ec6a061212c..2ddf3acd10584aa5213d3ae1288c911eb5182206 100644
--- a/ctrl/SlyEdit.cfg
+++ b/ctrl/SlyEdit.cfg
@@ -59,6 +59,11 @@ allowSpellCheck=true
 ; the same directory as SlyEdit.
 dictionaryFilenames=en
 
+; String settings - Currently, the only setting is the strings configuration
+; filename
+[STRINGS]
+stringsFilename=SlyEditStrings_En.cfg
+
 ; To use a different color theme file, change the ThemeFilename
 ; setting.  If you want, you can comment out the current setting
 ; (by placing a ; in front of the line) and un-commenting one
diff --git a/ctrl/SlyEditStrings_En.cfg b/ctrl/SlyEditStrings_En.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..dc159851d389ee59592474fe707ec9ac9a437ac5
--- /dev/null
+++ b/ctrl/SlyEditStrings_En.cfg
@@ -0,0 +1 @@
+areYouThere=\x01n\x01r\x01h\x01i@NAME@! \x01n\x01hAre you really there?\x01n
\ No newline at end of file
diff --git a/docs/SlyEdit_DD_Message_Lister_notes.txt b/docs/SlyEdit_DD_Message_Lister_notes.txt
deleted file mode 100644
index 463696c7bf3da323f303ba3cbd480da8358b9635..0000000000000000000000000000000000000000
--- a/docs/SlyEdit_DD_Message_Lister_notes.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-Digital Distortion Message Lister is now obsolete in favor of Digital
-Distortion Message Reader.  However, if you use Digital Distortion Message
-Lister, you must have version 1.36 in order for it to work properly with this
-version of SlyEdit.  The reason is due to the way SlyEdit looks up message
-header information to get author's initials when quoting messages, and due to
-information that Digital Distortion Message Lister provides to SlyEdit.
-Version 1.36 of the message lister now always writes the message number to its
-drop file (earlier versions wrote either the message number or message offset,
-depending on the version and build of Synchronet).  This version of SlyEdit
-simplified the way it decides to use the message number or offset and required
-the aforementioned change in Digital Distortion Message Lister.
-
-Below is a version table listing the required versions of Digital Distortion
-Message Lister with the recent versions of SlyEdit:
-
-SlyEdit      Digital Distortion message Lister
--------      ---------------------------------
-1.27+        1.36+
-1.26         1.35
-1.25         1.34
-1.18         1.31
-
-If you are using Digital Distortion Message Lister, you can download the Reader
-from eiether of the following URLs:
-http://www.digitaldistortionbbs.com/DigDistBBSStuff/DigDistBBSStuff.html
-http://digdist.bbsindex.com/DigDistBBSStuff/DigDistBBSStuff.html
\ No newline at end of file
diff --git a/docs/slyedit_readme.txt b/docs/slyedit_readme.txt
index d4480717d07496dc9a5297c9473aeed0be59f504..7a5ad1db79aee0fd028a4921ad11e2d487614386 100644
--- a/docs/slyedit_readme.txt
+++ b/docs/slyedit_readme.txt
@@ -1,6 +1,6 @@
                          SlyEdit message editor
-                              Version 1.89d
-                        Release date: 2025-01-26
+                              Version 1.89e
+                        Release date: 2025-02-09
 
                                   by
 
@@ -24,14 +24,15 @@ Contents
  3. Installation & Setup
  4. Features
  5. Configuration file
- 6. Ice-style Color Theme Settings
- 7. DCT-style Color Theme Settings
- 8. Common colors (appearing in both Ice and DCT color theme files)
- 9. Text replacements (AKA Macros)
-10. User settings
-11. Taglines
-12. Spell check and dictionaries
-13. Version history
+ 6. Strings configuration file
+ 7. Ice-style Color Theme Settings
+ 8. DCT-style Color Theme Settings
+ 9. Common colors (appearing in both Ice and DCT color theme files)
+10. Text replacements (AKA Macros)
+11. User settings
+12. Taglines
+13. Spell check and dictionaries
+14. Version history
 
 
 1. Disclaimer
@@ -392,6 +393,18 @@ dictionaryFilenames               Dictionary filenames (used for spell check).
                                   are located in either sbbs/mods, sbbs/ctrl,
                                   or the same directory as SlyEdit.
 
+String settings
+-----------------
+Setting                           Description
+-------                           -----------
+stringsFilename                   The name of the file containing text strings
+                                  displayed in SlyEdit. The default is
+                                  SlyEditStrings_En.cfg, which is located in
+                                  sbbs/ctrl - You can copy this to sbbs/mods and
+                                  keep a modified copy there if you want. The
+                                  strings in this file can contain Synchronet
+                                  attribute codes (prefixed with \x01).
+
 Ice colors
 ----------
 Setting                           Description
@@ -432,7 +445,21 @@ High green: gh
 Normal cyan: c
 
 
-6. Ice-style Color Theme Settings
+6. Strings configuration file
+=============================
+The strings configuration file (added in SlyEdit v1.89e, 2025-02-09) is a file
+similar in concept to text.dat, which is intended to contain strings displayed
+by SlyEdit. The format is like the other configuration files, in name=value
+format.
+
+Currently, the only configuratble string in there is areYouThere, which
+specifies a string to display for the input timeout warning (like item 668,
+AreYouThere in text.dat). The reason SlyEdit has its own version of this string
+is in case you decide to change the one in text.dat; for SlyEdit, it should be
+a string that can fit on one line on the screen.
+
+
+7. Ice-style Color Theme Settings
 =================================
 Note that you don't need control (Ctrl-A) characters for the color settings;
 just the attribute characters.
@@ -497,7 +524,7 @@ UnselectedOptionBorderColor       The color to use for the borders around
 UnselectedOptionTextColor         The color to use for the text for unselected
                                   multi-choice options
 
-7. DCT-style Color Theme Settings
+8. DCT-style Color Theme Settings
 =================================
 Note that you don't need control (Ctrl-A) characters for the color settings;
 just the attribute characters.
@@ -631,7 +658,7 @@ MenuUnselectedItems               The color to use for unselected items on the
 MenuHotkeys                       The color to use for the hotkey characters in the
                                   menu items on the drop-down menus
 
-8. Common colors (appearing in both Ice and DCT color theme files)
+9. Common colors (appearing in both Ice and DCT color theme files)
 ==================================================================
 Note that you don't need control (Ctrl-A) characters for the color settings;
 just the attribute characters.
@@ -721,7 +748,7 @@ listBoxItemHighlight              The color to use for the currently selected
                                   item in list boxes (such as the list of text
                                   replacements and the list of tag lines)
 
-9. Text replacements (AKA Macros)
+10. Text replacements (AKA Macros)
 ==================================
 SlyEdit version 1.29 added text replacements (AKA Macros), which lets you (the
 sysop) define words to be replaced with other text as the user types a message.
@@ -814,7 +841,7 @@ store it in buffer 1, and in JavaScript (and with SlyEdit's search and
 replace), you would use $1 to refer to the word "darn".  For example, for
 (darn), the replacement $1it would replace the word "darn" with "darnit".
 
-10. User settings
+11. User settings
 =================
 Since version 1.32, SlyEdit has the ability for each user to configure some
 settings for themselves.  The user settings include the following:
@@ -848,7 +875,7 @@ The user settings files will be stored in the sbbs/data/user directory with the
 filename <user number>.SlyEdit_Settings, and the user number will be 0-padded
 up to 4 digits.
 
-11. Taglines
+12. Taglines
 ============
 SlyEdit version 1.32 added the ability for users to optionally choose a tagline
 to be appended to their message upon saving the message.  Each user can
@@ -878,7 +905,7 @@ user's signature (if they have one).  If the MSGINF file does not include the
 7th line, then the tagline will appear before the user's signature.
 
 
-12. Spell check and dictionaries
+13. Spell check and dictionaries
 ================================
 Since version 1.64, SlyEdit has a spell check feature.  Spell check can be
 started by the user with the Ctrl-R hotkey, or by the Edit > Spell Checker
@@ -918,10 +945,15 @@ case, since SlyEdit does case-insensitive matching by converting words in the
 message to lower-case and comparing them with the words in the dictionary.
 
 
-13. Version history
+14. Version history
 ===================
 Version  Date         Description
 -------  ----         -----------
+1.89e    2025-02-09   User inactivity timeout: Display a warning message
+                      (without messing with the screen). New [STRINGS]
+                      configuration section with stringsFilename to specify the
+                      name of a strings file, which for now just contains an
+                      areYouThere setting
 1.89d    2025-01-26   User inactivity timeout improvement (via use of
                       console.getkey() instead of the custom function that was
                       being used)
diff --git a/exec/SlyEdit.js b/exec/SlyEdit.js
index ba3ce52e87b02bafd3c1c69654ae5057cf29921b..4aef4b639b916ba67591d49de61eca3da471b664 100644
--- a/exec/SlyEdit.js
+++ b/exec/SlyEdit.js
@@ -84,6 +84,11 @@
  * 2024-10-19 Eric Oulashin     Version 1.89d
  *                              User inactivity timeout improvement (via use of console.getkey()
  *                              instead of the custom function that was being used)
+ * 2025-02-09 Eric Oulashin     Version 1.89e
+ *                              User inactivity timeout: Display a warning message (without
+ *                              messing with the screen). New [STRINGS] configuration section
+ *                              with stringsFilename to specify the name of a strings file,
+ *                              which for now just contains an areYouThere setting
  */
 
 "use strict";
@@ -174,8 +179,8 @@ if (console.screen_columns < 80)
 }
 
 // Version information
-var EDITOR_VERSION = "1.89d";
-var EDITOR_VER_DATE = "2025-01-26";
+var EDITOR_VERSION = "1.89e";
+var EDITOR_VER_DATE = "2025-02-09";
 
 
 // Program variables
@@ -477,10 +482,57 @@ else
 js.on_exit("bbs.sys_status = " + bbs.sys_status);
 js.on_exit("console.ctrlkey_passthru = " + console.ctrlkey_passthru);
 
-// Blank out the AreYouThere timeout warning string (used by console.getkey()), which would
-// interfere with full-screen display and scrolling functionality. Also, upon exit, set it
-// back to its previous value.
-bbs.replace_text(AreYouThere, "");
+// Data for an "Are you there?" timeout warning handler
+js.global.slyEditData = {
+	bottomHelpLineRow: console.screen_rows,
+	useQuotes: gUseQuotes,
+	displayBottomhelpLine: fpDisplayBottomHelpLine,
+	replaceAtCodesInStr: replaceAtCodesInStr
+};
+Object.defineProperty(js.global, "SlyEdit_areYouThereProp", {
+	configurable: true, // Allows this property to be deleted and re-defined as needed
+	get: function()
+	{
+		// blank out the AreYouThere timeout warning string (used by
+		// console.getkey()), which would interfere with full-screen display and scrolling display
+		// functionality.
+		bbs.replace_text(AreYouThere, "");
+
+		var originalCurPos = console.getxy();
+		var originalAtrs = console.attributes;
+
+		console.beep();
+		var warningTxt = js.global.slyEditData.replaceAtCodesInStr(gConfigSettings.strings.areYouThere);
+		var numSpaces = Math.floor(console.screen_columns / 2) - Math.floor(console.strlen(warningTxt) / 2);
+		if (numSpaces > 0)
+			warningTxt = format("%*s", numSpaces, "") + warningTxt;
+		if (console.strlen(warningTxt) >= console.screen_columns)
+			warningTxt = warningTxt.substr(0, console.screen_columns-1);
+		warningTxt = "\x01n" + warningTxt;
+		console.gotoxy(1, js.global.slyEditData.bottomHelpLineRow);
+		console.print(warningTxt);
+		console.cleartoeol("\x01n");
+		mswait(1500);
+		js.global.slyEditData.displayBottomhelpLine(js.global.bottomHelpLineRow, js.global.useQuotes);
+
+		// Put a key into the input buffer so that Synchronet isn't waiting for
+		// a keypress after the "Are you there" warning
+		console.ungetstr(KEY_ENTER);
+
+		console.gotoxy(originalCurPos);
+		console.attributes = originalAtrs;
+
+		return "";
+	}
+});
+// Replace the system's AreYouThere text line with a @JS to show the
+// global SlyEdit_areYouThereProp property that has been set up
+// with a custom getter function to display "Are you there?" at a
+// good place on the screen temporarily and then refresh the screen.
+bbs.replace_text(AreYouThere, "@JS:SlyEdit_areYouThereProp@");
+// On script exit, delete the global SlyEdit_areYouThereProp property we have created
+js.on_exit("delete SlyEdit_areYouThereProp;");
+js.on_exit("delete js.global.slyEditData;");
 js.on_exit("bbs.revert_text(AreYouThere);");
 
 // Update the user's status on the BBS
@@ -1199,8 +1251,18 @@ function doEditLoop()
 	var continueOn = true;
 	while (continueOn)
 	{
+		// Get a key from the user
 		userInput = console.getkey(K_NOCRLF|K_NOSPIN|K_NUL);
 
+		// Replace the system's AreYouThere text line with a @JS to show the
+		// global SlyEdit_areYouThereProp property that has been set up
+		// with a custom getter function to display "Are you there?" at a
+		// good place on the screen temporarily and then refresh the screen.
+		// This is done here in the loop because the custom get function will
+		// replace AreYouThere with "" to prevent the screen from getting
+		// messy due to internal getkey() logic in Synchronet.
+		bbs.replace_text(AreYouThere, "@JS:SlyEdit_areYouThereProp@");
+
 		// If the cursor is at the end of the last line and the user
 		// pressed the DEL key, then treat it as a backspace.  Some
 		// terminals send a delete for backspace, particularly with
diff --git a/exec/SlyEdit_Misc.js b/exec/SlyEdit_Misc.js
index 08803abb4a41a925de5b7227f9c785d6eeaee41c..e9a1246795cb7def8f6220270759cc4559e0dbe1 100644
--- a/exec/SlyEdit_Misc.js
+++ b/exec/SlyEdit_Misc.js
@@ -1312,7 +1312,7 @@ function ChoiceScrollbox_SetBottomBorderText(pText, pAddTChars, pAutoStripIfTooL
 	this.bottomBorder += pText + "\x01n" + this.SlyEdCfgObj.genColors.listBoxBorder;
 	if (pAddTChars)
 		this.bottomBorder += LEFT_T_SINGLE;
-	var numCharsRemaining = this.dimensions.width - console.strlen(this.bottomBorder) - 3;
+	var numCharsRemaining = this.dimensions.width - console.strlen(this.bottomBorder) - 1;
 	for (var i = 0; i < numCharsRemaining; ++i)
 		this.bottomBorder += HORIZONTAL_SINGLE;
 	this.bottomBorder += LOWER_RIGHT_SINGLE;
@@ -2146,7 +2146,6 @@ function ReadSlyEditConfigFile()
 		thirdPartyLoadOnExit: [],
 		runJSOnExit: [],
 		displayEndInfoScreen: true,
-		userInputTimeout: true,
 		reWrapQuoteLines: true,
 		allowColorSelection: true,
 		saveColorsAsANSI: false,
@@ -2275,9 +2274,16 @@ function ReadSlyEditConfigFile()
 			MenuSelectedItems: "\x01n\x01w",
 			MenuUnselectedItems: "\x01n\x01k\x01" + "7",
 			MenuHotkeys: "\x01n\x01w\x01h\x01" + "7"
+		},
+
+		strings: {
+			areYouThere: "\x01n\x01r\x01h\x01i@NAME@! \x01n\x01hAre you really there?\x01n"
 		}
 	};
 
+	// Default strings configuration filename
+	var stringsCfgFilename = genFullPathCfgFilename("SlyEditStrings_En.cfg", js.exec_dir);
+
 	// Open the SlyEdit configuration file
 	var slyEdCfgFileName = genFullPathCfgFilename("SlyEdit.cfg", js.exec_dir);
 	var cfgFile = new File(slyEdCfgFileName);
@@ -2285,69 +2291,101 @@ function ReadSlyEditConfigFile()
 	{
 		// Behavior settings
 		var behaviorSettings = cfgFile.iniGetObject("BEHAVIOR");
-		// The following are all boolean properties/settings:
-		var propsToCopy = ["displayEndInfoScreen", "userInputTimeout", "reWrapQuoteLines", "allowColorSelection",
-		                   "saveColorsAsANSI", "useQuoteLineInitials", "indentQuoteLinesWithInitials", "allowCrossPosting",
-		                   "enableTaglines", "quoteTaglines", "shuffleTaglines", "allowUserSettings", "allowEditQuoteLines",
-		                   "allowSpellCheck"];
-		for (var i = 0; i < propsToCopy.length; ++i)
+		// Text strings
+		var stringsSettings = cfgFile.iniGetObject("STRINGS");
+		// Color settings
+		var iceColorSettings = cfgFile.iniGetObject("ICE_COLORS");
+		var DCTColorSettings = cfgFile.iniGetObject("DCT_COLORS");
+		cfgFile.close();
+
+		// Checking/setting: Behavior
+		if (behaviorSettings != null)
+		{
+			// The following are all boolean properties/settings:
+			var propsToCopy = ["displayEndInfoScreen", "reWrapQuoteLines", "allowColorSelection", "saveColorsAsANSI",
+			                   "useQuoteLineInitials", "indentQuoteLinesWithInitials", "allowCrossPosting", "enableTaglines",
+			                   "quoteTaglines", "shuffleTaglines", "allowUserSettings", "allowEditQuoteLines", "allowSpellCheck"];
+			for (var i = 0; i < propsToCopy.length; ++i)
+			{
+				var propName = propsToCopy[i];
+				cfgObj[propName] = behaviorSettings[propName];
+			}
+			// Other settings:
+			if (behaviorSettings.hasOwnProperty("add3rdPartyStartupScript") && typeof(behaviorSettings.add3rdPartyStartupScript) === "string")
+				cfgObj.thirdPartyLoadOnStart.push(behaviorSettings.add3rdPartyStartupScript);
+			if (behaviorSettings.hasOwnProperty("addJSOnStart") && typeof(behaviorSettings.addJSOnStart) === "string")
+				cfgObj.runJSOnStart.push(behaviorSettings.addJSOnStart);
+			if (behaviorSettings.hasOwnProperty("addJSOnExit") && typeof(behaviorSettings.addJSOnExit) === "string")
+				cfgObj.runJSOnExit.push(behaviorSettings.addJSOnExit);
+			if (behaviorSettings.hasOwnProperty("enableTextReplacements"))
+			{
+				// The enableTxtReplacements setting in the config file can
+				// be regex, true, or false:
+				//  - regex: Text replacement enabled using regular expressions
+				//  - true: Text replacement enabled using exact match
+				//  - false: Text replacement disabled
+				if (typeof(behaviorSettings.enableTextReplacements) === "string")
+					cfgObj.textReplacementsUseRegex = (behaviorSettings.enableTextReplacements.toUpperCase() == "REGEX");
+				else if (typeof(behaviorSettings.enableTextReplacements) === "boolean")
+					cfgObj.enableTextReplacements = behaviorSettings.enableTextReplacements;
+				if (cfgObj.textReplacementsUseRegex)
+					cfgObj.enableTextReplacements = true;
+			}
+			if (behaviorSettings.hasOwnProperty("tagLineFilename") && typeof(behaviorSettings.tagLineFilename) === "string")
+				cfgObj.tagLineFilename = genFullPathCfgFilename(behaviorSettings.tagLineFilename, js.exec_dir);
+			if (behaviorSettings.hasOwnProperty("taglinePrefix") && typeof(behaviorSettings.taglinePrefix) === "string")
+				cfgObj.taglinePrefix = behaviorSettings.taglinePrefix;
+			if (behaviorSettings.hasOwnProperty("dictionaryFilenames") && typeof(behaviorSettings.dictionaryFilenames) === "string")
+				cfgObj.dictionaryFilenames = parseDictionaryConfig(behaviorSettings.dictionaryFilenames, js.exec_dir);
+		}
+
+		// Color settings
+		if (iceColorSettings != null)
 		{
-			var propName = propsToCopy[i];
-			cfgObj[propName] = behaviorSettings[propName];
+			if (iceColorSettings.hasOwnProperty("ThemeFilename") && typeof(iceColorSettings.ThemeFilename) === "string")
+				cfgObj.iceColors.ThemeFilename = genFullPathCfgFilename(iceColorSettings.ThemeFilename, js.exec_dir);
+			if (iceColorSettings.hasOwnProperty("menuOptClassicColors") && typeof(iceColorSettings.menuOptClassicColors) === "boolean")
+				cfgObj.iceColors.menuOptClassicColors = iceColorSettings.menuOptClassicColors; // This is a boolean
 		}
-		// Other settings:
-		if (behaviorSettings.hasOwnProperty("add3rdPartyStartupScript") && typeof(behaviorSettings.add3rdPartyStartupScript) === "string")
-			cfgObj.thirdPartyLoadOnStart.push(behaviorSettings.add3rdPartyStartupScript);
-		if (behaviorSettings.hasOwnProperty("addJSOnStart") && typeof(behaviorSettings.addJSOnStart) === "string")
-			cfgObj.runJSOnStart.push(behaviorSettings.addJSOnStart);
-		if (behaviorSettings.hasOwnProperty("addJSOnExit") && typeof(behaviorSettings.addJSOnExit) === "string")
-			cfgObj.runJSOnExit.push(behaviorSettings.addJSOnExit);
-		if (behaviorSettings.hasOwnProperty("enableTextReplacements"))
+		if (DCTColorSettings != null)
 		{
-			// The enableTxtReplacements setting in the config file can
-			// be regex, true, or false:
-			//  - regex: Text replacement enabled using regular expressions
-			//  - true: Text replacement enabled using exact match
-			//  - false: Text replacement disabled
-			if (typeof(behaviorSettings.enableTextReplacements) === "string")
-				cfgObj.textReplacementsUseRegex = (behaviorSettings.enableTextReplacements.toUpperCase() == "REGEX");
-			else if (typeof(behaviorSettings.enableTextReplacements) === "boolean")
-				cfgObj.enableTextReplacements = behaviorSettings.enableTextReplacements;
-			if (cfgObj.textReplacementsUseRegex)
-				cfgObj.enableTextReplacements = true;
+			if (DCTColorSettings.hasOwnProperty("ThemeFilename") && typeof(DCTColorSettings.ThemeFilename) === "string")
+				cfgObj.DCTColors.ThemeFilename = genFullPathCfgFilename(DCTColorSettings.ThemeFilename, js.exec_dir);
 		}
-		if (behaviorSettings.hasOwnProperty("tagLineFilename") && typeof(behaviorSettings.tagLineFilename) === "string")
-			cfgObj.tagLineFilename = genFullPathCfgFilename(behaviorSettings.tagLineFilename, js.exec_dir);
-		if (behaviorSettings.hasOwnProperty("taglinePrefix") && typeof(behaviorSettings.taglinePrefix) === "string")
-			cfgObj.taglinePrefix = behaviorSettings.taglinePrefix;
-		if (behaviorSettings.hasOwnProperty("dictionaryFilenames") && typeof(behaviorSettings.dictionaryFilenames) === "string")
-			cfgObj.dictionaryFilenames = parseDictionaryConfig(behaviorSettings.dictionaryFilenames, js.exec_dir);
-		// Color settings
-		var iceColorSettings = cfgFile.iniGetObject("ICE_COLORS");
-		var DCTColorSettings = cfgFile.iniGetObject("DCT_COLORS");
-		if (typeof(cfgObj.iceColors) !== "object")
-			cfgObj.iceColors = {};
-		if (typeof(cfgObj.DCTColors) !== "object")
-			cfgObj.DCTColors = {};
-		if (iceColorSettings.hasOwnProperty("ThemeFilename") && typeof(iceColorSettings.ThemeFilename) === "string")
-			cfgObj.iceColors.ThemeFilename = genFullPathCfgFilename(iceColorSettings.ThemeFilename, js.exec_dir);
-		if (iceColorSettings.hasOwnProperty("menuOptClassicColors") && typeof(iceColorSettings.menuOptClassicColors) === "boolean")
-			cfgObj.iceColors.menuOptClassicColors = iceColorSettings.menuOptClassicColors; // This is a boolean
-		if (DCTColorSettings.hasOwnProperty("ThemeFilename") && typeof(DCTColorSettings.ThemeFilename) === "string")
-			cfgObj.DCTColors.ThemeFilename = genFullPathCfgFilename(DCTColorSettings.ThemeFilename, js.exec_dir);
 
-		cfgFile.close();
+		// If there is a strings filename, then set stringsCfgFilename
+		if (stringsSettings != null && stringsSettings.hasOwnProperty("stringsFilename") && typeof(stringsSettings.stringsFilename) === "string")
+			stringsCfgFilename = genFullPathCfgFilename(stringsSettings.stringsFilename, js.exec_dir);
+	}
 
-		// If no dictionaries were specified in the configuration file, then
-		// set all available dictionary files in the configuration.
-		if (cfgObj.dictionaryFilenames.length == 0)
+	// If the strings configuration file exists, then load and read it
+	if (file_exists(stringsCfgFilename))
+	{
+		var stringsFile = new File(stringsCfgFilename);
+		if (stringsFile.open("r"))
 		{
-			var dictFilenames = getDictionaryFilenames(js.exec_dir);
-			for (var i = 0; i < dictFilenames.length; ++i)
-				cfgObj.dictionaryFilenames.push(dictFilenames[i]);
+			var stringsSettingsObj = stringsFile.iniGetObject();
+			stringsFile.close();
+			for (var prop in cfgObj.strings)
+			{
+				if (typeof(stringsSettingsObj[prop]) === "string" && stringsSettingsObj[prop].length > 0)
+				{
+					// Replace "\x01" with control character
+					cfgObj.strings[prop] = stringsSettingsObj[prop].replace(/\\x01/g, "\x01");
+				}
+			}
 		}
 	}
 
+	// If no dictionaries were specified in the configuration file, then
+	// set all available dictionary files in the configuration.
+	if (cfgObj.dictionaryFilenames.length == 0)
+	{
+		var dictFilenames = getDictionaryFilenames(js.exec_dir);
+		for (var i = 0; i < dictFilenames.length; ++i)
+			cfgObj.dictionaryFilenames.push(dictFilenames[i]);
+	}
+
 	return cfgObj;
 }
 
@@ -5626,6 +5664,26 @@ function getEditorQuoteWrapCfgFromSCFG()
 	return retObj;
 }
 
+// Replaces @-codes in a string and returns the new string.
+//
+// Parameters:
+//  pStr: A string in which to replace @-codes
+//
+// Return value: A version of the string with @-codes interpreted
+function replaceAtCodesInStr(pStr)
+{
+	if (typeof(pStr) != "string")
+		return "";
+
+	// This code was originally written by Deuce.  I updated it to check whether
+	// the string returned by bbs.atcode() is null, and if so, just return
+	// the original string.
+	return pStr.replace(/@([^@]+)@/g, function(m, code) {
+		var decoded = bbs.atcode(code);
+		return (decoded != null ? decoded : "@" + code + "@");
+	});
+}
+
 // This function displays debug text at a given location on the screen, then
 // moves the cursor back to a given location.
 //
diff --git a/exec/slyedcfg.js b/exec/slyedcfg.js
index fb92de680bcf3e759dd95113214f6e091e0b7a1e..7929861751ee3e817a0183aa82172268c63f8ca3 100644
--- a/exec/slyedcfg.js
+++ b/exec/slyedcfg.js
@@ -1,7 +1,7 @@
 // SlyEdit configurator: This is a menu-driven configuration program/script for SlyEdit.
 // Any changes are saved to SlyEdit.cfg in sbbs/mods, so that custom changes don't get
 // overridden with SlyEdit.cfg in sbbs/ctrl due to an update.
-// Currently for SlyEdit 1.89b.
+// Currently for SlyEdit 1.89e.
 
 "use strict";
 
@@ -10,7 +10,7 @@ require("sbbsdefs.js", "P_NONE");
 require("uifcdefs.js", "UIFC_INMSG");
 
 
-if (!uifc.init("SlyEdit 1.89d Configurator"))
+if (!uifc.init("SlyEdit 1.89e Configurator"))
 {
 	print("Failed to initialize uifc");
 	exit(1);
@@ -61,7 +61,7 @@ function doMainMenu()
 {
 	// Create a CTX to specify the current selected item index
 	var ctx = uifc.list.CTX();
-	var helpText = "Behavior: Behavior settings\r\nIce Colors: Ice-related color settings\r\nDCT Colors: DCT-related color settings";
+	var helpText = "Behavior: Behavior settings\r\nStrings: Text string configuration\r\nIce Colors: Ice-related color settings\r\nDCT Colors: DCT-related color settings";
 	// Selection
 	var winMode = WIN_ORG|WIN_MID|WIN_ACT|WIN_ESC;
 	var menuTitle = "SlyEdit Configuration";
@@ -70,7 +70,7 @@ function doMainMenu()
 	while (continueOn && !js.terminated)
 	{
 		uifc.help_text = word_wrap(helpText, gHelpWrapWidth);
-		var selection = uifc.list(winMode, menuTitle, ["Behavior", "Ice Colors", "DCT Colors"], ctx);
+		var selection = uifc.list(winMode, menuTitle, ["Behavior", "Strings", "Ice Colors", "DCT Colors"], ctx);
 		ctx.cur = selection; // Remember the current selected item
 		switch (selection)
 		{
@@ -80,10 +80,13 @@ function doMainMenu()
 			case 0: // Behavior
 				anyOptionChanged = doBehaviorMenu() || anyOptionChanged;
 				break;
-			case 1: // Ice colors
+			case 1: // Strings
+				anyOptionChanged = doStringsMenu() || anyOptionChanged;
+				break;
+			case 2: // Ice colors
 				anyOptionChanged = doIceColors() || anyOptionChanged;
 				break;
-			case 2: // DCT colors
+			case 3: // DCT colors
 				anyOptionChanged = doDCTColors() || anyOptionChanged;
 				break;
 		}
@@ -91,6 +94,45 @@ function doMainMenu()
 	return anyOptionChanged;
 }
 
+// Configuration menu for the [STRINGS] section
+function doStringsMenu()
+{
+	// For menu item text formatting
+	var itemTextMaxLen = 40;
+
+	// Create a CTX to specify the current selected item index
+	var ctx = uifc.list.CTX();
+	var helpText = "Strings filename: The filename containing the configurable strings";
+	// Selection
+	var winMode = WIN_ORG|WIN_MID|WIN_ACT|WIN_ESC;
+	var menuTitle = "String section configuration";
+	var anyOptionChanged = false;
+	var continueOn = true;
+	while (continueOn && !js.terminated)
+	{
+		uifc.help_text = word_wrap(helpText, gHelpWrapWidth);
+		var menuItems = [];
+		menuItems.push(formatCfgMenuText(itemTextMaxLen, "Strings filename", gCfgInfo.cfgSections.STRINGS.stringsFilename));
+		var selection = uifc.list(winMode, menuTitle, menuItems, ctx);
+		ctx.cur = selection; // Remember the current selected item
+		switch (selection)
+		{
+			case -1: // ESC
+				continueOn = false;
+				break;
+			case 0: // Strings filename
+				var userInput = uifc.input(WIN_MID, "Strings filename", gCfgInfo.cfgSections.STRINGS.stringsFilename, 60, K_EDIT);
+				if (typeof(userInput) === "string" && userInput != gCfgInfo.cfgSections.STRINGS.stringsFilename)
+				{
+					gCfgInfo.cfgSections.STRINGS.stringsFilename = userInput;
+					anyOptionChanged = true;
+				}
+				break;
+		}
+	}
+	return anyOptionChanged;
+}
+
 // Allows the user to change behavior settings.
 // Returns whether any option changed (boolean).
 function doBehaviorMenu()
@@ -725,6 +767,13 @@ function readSlyEditCfgFile()
 	if (!retObj.cfgSections.BEHAVIOR.hasOwnProperty("dictionaryFilenames"))
 		retObj.cfgSections.BEHAVIOR.dictionaryFilenames = "en,en-US-supplemental";
 
+	if (!retObj.cfgSections.hasOwnProperty("STRINGS"))
+	{
+		retObj.cfgSections.STRINGS = {
+			stringsFilename: "SlyEditStrings_En.cfg"
+		};
+	}
+
 	if (!retObj.cfgSections.hasOwnProperty("ICE_COLORS"))
 		retObj.cfgSections.ICE_COLORS = {};
 	if (!retObj.cfgSections.ICE_COLORS.hasOwnProperty("menuOptClassicColors"))
@@ -767,11 +816,12 @@ function saveSlyEditCfgFile()
 	if (cfgFile.open(cfgFile.exists ? "r+" : "w+")) // r+: Reading and writing (file must exist)
 	{
 		var behaviorSetSuccessful = cfgFile.iniSetObject("BEHAVIOR", gCfgInfo.cfgSections.BEHAVIOR);
+		var stringsSetSuccessful = cfgFile.iniSetObject("STRINGS", gCfgInfo.cfgSections.STRINGS);
 		var iceColorsSetSuccessful = cfgFile.iniSetObject("ICE_COLORS", gCfgInfo.cfgSections.ICE_COLORS);
 		var dctColorsSetSuccessful = cfgFile.iniSetObject("DCT_COLORS", gCfgInfo.cfgSections.DCT_COLORS);
 
 		cfgFile.close();
-		saveSucceeded = behaviorSetSuccessful && iceColorsSetSuccessful && dctColorsSetSuccessful;
+		saveSucceeded = behaviorSetSuccessful && stringsSetSuccessful && iceColorsSetSuccessful && dctColorsSetSuccessful;
 	}
 
 	return saveSucceeded;