diff --git a/xtrn/DDMsgReader/DDMsgReader.js b/xtrn/DDMsgReader/DDMsgReader.js
index a88eddf8702a6c999146bebdc179a74dd541b7cb..5213c46dfc57f7ae15e910661c988c730a8224d0 100644
--- a/xtrn/DDMsgReader/DDMsgReader.js
+++ b/xtrn/DDMsgReader/DDMsgReader.js
@@ -120,6 +120,15 @@
  *                              now lists ALL sub-boards, rather than only sub-boards the user has enabled
  *                              for newscan. It also prompts the user to list sub-boards in the current group
  *                              or all.
+ * 2024-01-04 Eric Oulashin     Version 1.93a Beta
+ *                              Fix: For indexed read mode (not doing a newscan), when choosing a sub-board to
+ *                              read, the correct (first unread) message is displayed. Also, the user's scan
+ *                              pointer is also updated to the last_read pointer.
+ * 2024-01-08 Eric Oulashin     Version 1.94
+ *                              New operator option for read mode: Add author email to email.can.
+ *                              New command-line option: -indexModeScope, which can specify the indexed
+ *                              reader scope (group/all) without prompting the user.
+ *                              User configuration options for newscan & email only shown when doing those actions
  */
 
 "use strict";
@@ -225,8 +234,8 @@ var hexdump = load('hexdump_lib.js');
 
 
 // Reader version information
-var READER_VERSION = "1.93";
-var READER_DATE = "2024-01-01";
+var READER_VERSION = "1.94";
+var READER_DATE = "2024-01-08";
 
 // Keyboard key codes for displaying on the screen
 var UP_ARROW = ascii(24);
@@ -568,14 +577,26 @@ if (gDoDDMR)
 	{
 		console.attributes = "N";
 		console.crlf();
-		console.mnemonics("Indexed read: ~Group: @GRP@, or ~@All@: ");
-		var scopeChar = console.getkeys("GA").toString();
+		var scopeChar = "";
+		if (typeof(gCmdLineArgVals.indexmodescope) === "string")
+		{
+			var argScopeLower = gCmdLineArgVals.indexmodescope.toLowerCase();
+			if (argScopeLower == "group" || argScopeLower == "grp")
+				scopeChar = "G";
+			else if (argScopeLower == "all")
+				scopeChar = "A";
+		}
+		if (scopeChar == "")
+		{
+			console.mnemonics("Indexed read: ~Group: @GRP@, or ~@All@: ");
+			scopeChar = console.getkeys("GA").toString();
+		}
 		if (typeof(scopeChar) === "string" && scopeChar != "")
 		{
 			var scanScope = SCAN_SCOPE_ALL;
 			if (scopeChar == "G")
 				scanScope = SCAN_SCOPE_GROUP;
-			else if (scopeChar == "G")
+			else if (scopeChar == "A")
 				scanScope = SCAN_SCOPE_ALL;
 			msgReader.DoIndexedMode(scanScope, false);
 		}
@@ -1076,10 +1097,10 @@ function DigDistMsgReader(pSubBoardCode, pScriptArgs)
 		userSettings: CTRL_U,
 		validateMsg: "A", // Only if the user is a sysop
 		quickValUser: CTRL_Q,
+		threadView: "*", // TODO: Implement this
 		operatorMenu: CTRL_O,
 		showMsgHex: "X",
-		hexDump: CTRL_X,
-		threadView: "*" // TODO: Implement this
+		hexDump: CTRL_X
 	};
 	//if (user.is_sysop)
 	//	this.enhReaderKeys.validateMsg = "A";
@@ -1570,8 +1591,13 @@ function DigDistMsgReader(pSubBoardCode, pScriptArgs)
 		showMsgHex: 5,
 		saveMsgHexToFile: 6,
 		quickValUser: 7,
-		addAuthorToTwitList: 8
+		addAuthorToTwitList: 8,
+		addAuthorEmailToEmailFilter: 9
 	};
+
+	// For indexed mode, whether to set the indexed mode menu item index to 1 more when showing
+	// the indexed mode menu again (i.e., when the user wants to go to the next sub-board)
+	this.indexedModeSetIdxMnuIdxOneMore = false;
 }
 
 // For the DigDistMsgReader class: Sets the subBoardCode property and also
@@ -6438,6 +6464,24 @@ function DigDistMsgReader_ReadMessageEnhanced_Scrollable(msgHeader, allowChgMsgA
 									this.DisplayEnhancedMsgReadHelpLine(console.screen_rows, allowChgMsgArea);
 								}
 								break;
+							case this.readerOpMenuOptValues.addAuthorEmailToEmailFilter:
+								var fromEmailAddr = "";
+								if (typeof(msgHeader.from_net_addr) === "string" && msgHeader.from_net_addr.length > 0)
+								{
+									if (msgHeader.from_net_type == NET_INTERNET)
+										fromEmailAddr = msgHeader.from_net_addr;
+									else
+										fromEmailAddr = msgHeader.from + "@" + msgHeader.from_net_addr;
+								}
+								var promptTxt = format("Add %s to global email filter", fromEmailAddr);
+								if (this.EnhReaderPromptYesNo(promptTxt, msgInfo.messageLines, topMsgLineIdx, msgLineFormatStr, solidBlockStartRow, numSolidScrollBlocks, true))
+								{
+									var statusMsg = "\x01n" + addToGlobalEmailFilter(fromEmailAddr) ? "\x01w\x01hSuccessfully updated the email filter" : "\x01y\x01hFailed to update the email filter!"
+									writeWithPause(1, console.screen_rows, statusMsg, ERROR_PAUSE_WAIT_MS, "\x01n", true);
+									console.attributes = "N";
+									this.DisplayEnhancedMsgReadHelpLine(console.screen_rows, allowChgMsgArea);
+								}
+								break;
 						}
 					}
 				}
@@ -7758,6 +7802,25 @@ function DigDistMsgReader_ReadMessageEnhanced_Traditional(msgHeader, allowChgMsg
 									console.pause();
 								}
 								break;
+							case this.readerOpMenuOptValues.addAuthorEmailToEmailFilter:
+								var fromEmailAddr = "";
+								if (typeof(msgHeader.from_net_addr) === "string" && msgHeader.from_net_addr.length > 0)
+								{
+									if (msgHeader.from_net_type == NET_INTERNET)
+										fromEmailAddr = msgHeader.from_net_addr;
+									else
+										fromEmailAddr = msgHeader.from + "@" + msgHeader.from_net_addr;
+								}
+								var promptTxt = format("Add %s to global email filter", fromEmailAddr);
+								if (!console.noyes(promptTxt))
+								{
+									var statusMsg = "\x01n" + addToGlobalEmailFilter(fromEmailAddr) ? "\x01w\x01hSuccessfully updated the email filter" : "\x01y\x01hFailed to update the email filter!"
+									console.print(statusMsg);
+									console.attributes = "N";
+									console.crlf();
+									console.pause();
+								}
+								break;
 						}
 					}
 				}
@@ -7849,7 +7912,7 @@ function DigDistMsgReader_CreateReadModeOpMenu()
 	var subBoardIsModerated = (this.subBoardCode != "mail" && msg_area.sub[this.subBoardCode].is_moderated);
 
 	var opMenuWidth = 35;
-	var opMenuHeight = 10;
+	var opMenuHeight = 11;
 	if (subBoardIsModerated)
 		++opMenuHeight;
 	var opMenuX = Math.floor(console.screen_columns/2) - Math.floor(opMenuWidth/2);
@@ -7872,6 +7935,7 @@ function DigDistMsgReader_CreateReadModeOpMenu()
 		opMenu.Add("&E: Save message hex to file", this.readerOpMenuOptValues.saveMsgHexToFile);
 		opMenu.Add("&A: Quick validate the user", this.readerOpMenuOptValues.quickValUser);
 		opMenu.Add("&I: Add author to twit list", this.readerOpMenuOptValues.addAuthorToTwitList);
+		opMenu.Add("&M: Add author to email filter", this.readerOpMenuOptValues.addAuthorEmailToEmailFilter);
 		// Use cyan for the item color, and cyan with blue background for selected item color
 		opMenu.colors.itemColor = "\x01n\x01c";
 		opMenu.colors.selectedItemColor = "\x01n\x01c\x014";
@@ -7886,6 +7950,7 @@ function DigDistMsgReader_CreateReadModeOpMenu()
 		opMenu.Add("Save message hex to file", this.readerOpMenuOptValues.saveMsgHexToFile);
 		opMenu.Add("Quick validate the user", this.readerOpMenuOptValues.quickValUser);
 		opMenu.Add("Add author to twit list", this.readerOpMenuOptValues.addAuthorToTwitList);
+		opMenu.Add("Add author to email filter", this.readerOpMenuOptValues.addAuthorEmailToEmailFilter);
 		// Use green for the item color and high cyan for the item number color
 		opMenu.colors.itemColor = "\x01n\x01g";
 		opMenu.colors.itemNumColor = "\x01n\x01c\x01h";
@@ -14922,7 +14987,11 @@ function DigDistMsgReader_DoUserSettings_Scrollable(pDrawBottomhelpLineFn, pTopR
 	// Create the user settings box
 	var optBoxTitle = "Setting                                      Enabled";
 	var optBoxWidth = ChoiceScrollbox_MinWidth();
-	var optBoxHeight = 14;
+	var optBoxHeight = 10;
+	if (this.doingNewscan)
+		optBoxHeight += 3;
+	if (this.readingPersonalEmail)
+		++optBoxHeight;
 	var msgBoxTopRow = 1;
 	if (typeof(pTopRowOverride) === "number" && pTopRowOverride >= 1 && pTopRowOverride <= console.screen_rows - optBoxHeight + 1)
 		msgBoxTopRow = pTopRowOverride;
@@ -14964,17 +15033,24 @@ function DigDistMsgReader_DoUserSettings_Scrollable(pDrawBottomhelpLineFn, pTopR
 	if (this.userSettings.useIndexedModeForNewscan)
 		optionBox.chgCharInTextItem(INDEXED_MODE_NEWSCAN_OPT_INDEX, checkIdx, CHECK_CHAR);
 
-	const SHOW_INDEXED_NEWSCAN_MENU_IF_NO_NEW_MSGS_OPT_INDEX = optionBox.addTextItem(format(optionFormatStr, "Show indexed menu if there are no new messages"));
-	if (this.userSettings.displayIndexedModeMenuIfNoNewMessages)
-		optionBox.chgCharInTextItem(SHOW_INDEXED_NEWSCAN_MENU_IF_NO_NEW_MSGS_OPT_INDEX, checkIdx, CHECK_CHAR);
+	// Indexed-mode newscan options
+	var SHOW_INDEXED_NEWSCAN_MENU_IF_NO_NEW_MSGS_OPT_INDEX = -1;
+	var INDEXED_MODE_NEWSCAN_MENU_AFTER_READING_ALL_NEW_MSGS_OPT_INDEX = -1;
+	var INDEXED_MODE_MENU_SNAP_TO_NEW_MSGS_OPT_INDEX = -1;
+	if (this.doingNewscan)
+	{
+		SHOW_INDEXED_NEWSCAN_MENU_IF_NO_NEW_MSGS_OPT_INDEX = optionBox.addTextItem(format(optionFormatStr, "Show indexed menu if there are no new messages"));
+		if (this.userSettings.displayIndexedModeMenuIfNoNewMessages)
+			optionBox.chgCharInTextItem(SHOW_INDEXED_NEWSCAN_MENU_IF_NO_NEW_MSGS_OPT_INDEX, checkIdx, CHECK_CHAR);
 
-	const INDEXED_MODE_NEWSCAN_MENU_AFTER_READING_ALL_NEW_MSGS_OPT_INDEX = optionBox.addTextItem(format(optionFormatStr, "Show indexed menu after reading all new msgs"));
-	if (this.userSettings.showIndexedNewscanMenuAfterReadingAllNewMsgs)
-		optionBox.chgCharInTextItem(INDEXED_MODE_NEWSCAN_MENU_AFTER_READING_ALL_NEW_MSGS_OPT_INDEX, checkIdx, CHECK_CHAR);
+		INDEXED_MODE_NEWSCAN_MENU_AFTER_READING_ALL_NEW_MSGS_OPT_INDEX = optionBox.addTextItem(format(optionFormatStr, "Show indexed menu after reading all new msgs"));
+		if (this.userSettings.showIndexedNewscanMenuAfterReadingAllNewMsgs)
+			optionBox.chgCharInTextItem(INDEXED_MODE_NEWSCAN_MENU_AFTER_READING_ALL_NEW_MSGS_OPT_INDEX, checkIdx, CHECK_CHAR);
 
-	const INDEXED_MODE_MENU_SNAP_TO_NEW_MSGS_OPT_INDEX = optionBox.addTextItem(format(optionFormatStr, "Index menu: Snap to sub-boards w/ new messages"));
-	if (this.userSettings.indexedModeMenuSnapToFirstWithNew)
-		optionBox.chgCharInTextItem(INDEXED_MODE_MENU_SNAP_TO_NEW_MSGS_OPT_INDEX, checkIdx, CHECK_CHAR);
+		INDEXED_MODE_MENU_SNAP_TO_NEW_MSGS_OPT_INDEX = optionBox.addTextItem(format(optionFormatStr, "Index newscan: Snap to sub-boards w/ new msgs"));
+		if (this.userSettings.indexedModeMenuSnapToFirstWithNew)
+			optionBox.chgCharInTextItem(INDEXED_MODE_MENU_SNAP_TO_NEW_MSGS_OPT_INDEX, checkIdx, CHECK_CHAR);
+	}
 
 	const INDEX_NEWSCAN_ENTER_SHOWS_MSG_LIST_OPT_INDEX = optionBox.addTextItem(format(optionFormatStr, "Index menu: Enter shows message list"));
 	if (this.userSettings.enterFromIndexMenuShowsMsgList)
@@ -14988,9 +15064,14 @@ function DigDistMsgReader_DoUserSettings_Scrollable(pDrawBottomhelpLineFn, pTopR
 	if (this.userSettings.promptDelPersonalEmailAfterReply)
 		optionBox.chgCharInTextItem(PROPMT_DEL_PERSONAL_MSG_AFTER_REPLY_OPT_INDEX, checkIdx, CHECK_CHAR);
 
-	const DISPLAY_PERSONAL_MAIL_REPLIED_INDICATOR_CHAR_OPT_INDEX = optionBox.addTextItem(format(optionFormatStr, "Display email 'replied' indicator"));
-	if (this.userSettings.displayMsgRepliedChar)
-		optionBox.chgCharInTextItem(DISPLAY_PERSONAL_MAIL_REPLIED_INDICATOR_CHAR_OPT_INDEX, checkIdx, CHECK_CHAR);
+	// Specific to personal email
+	var DISPLAY_PERSONAL_MAIL_REPLIED_INDICATOR_CHAR_OPT_INDEX = -1;
+	if (this.readingPersonalEmail)
+	{
+		DISPLAY_PERSONAL_MAIL_REPLIED_INDICATOR_CHAR_OPT_INDEX = optionBox.addTextItem(format(optionFormatStr, "Display email 'replied' indicator"));
+		if (this.userSettings.displayMsgRepliedChar)
+			optionBox.chgCharInTextItem(DISPLAY_PERSONAL_MAIL_REPLIED_INDICATOR_CHAR_OPT_INDEX, checkIdx, CHECK_CHAR);
+	}
 
 	// Create an object containing toggle values (true/false) for each option index
 	var optionToggles = {};
@@ -15147,17 +15228,31 @@ function DigDistMsgReader_DoUserSettings_Traditional()
 		userTwitListChanged: false
 	};
 
-	var LIST_MESSAGES_IN_REVERSE_OPT_NUM = 1;
-	var NEWSCAN_ONLY_SHOW_NEW_MSGS_OPT_NUM = 2;
-	var USE_INDEXED_MODE_FOR_NEWSCAN_OPT_NUM = 3;
-	var SHOW_INDEXED_NEWSCAN_MENU_IF_NO_NEW_MSGS_OPT_NUM = 4;
-	var INDEXED_MODE_NEWSCAN_MENU_AFTER_READING_ALL_NEW_MSGS_OPT_INDEX = 5;
-	var INDEX_NEWSCAN_ENTER_SHOWS_MSG_LIST_OPT_NUM = 6;
-	var READER_QUIT_TO_MSG_LIST_OPT_NUM = 7;
-	var PROPMT_DEL_PERSONAL_MSG_AFTER_REPLY_OPT_NUM = 8;
-	var DISPLAY_PERSONAL_MAIL_REPLIED_INDICATOR_CHAR_OPT_NUM = 9;
-	var USER_TWITLIST_OPT_NUM = 10;
-	var HIGHEST_CHOICE_NUM = USER_TWITLIST_OPT_NUM;
+	var optNum = 1;
+	var LIST_MESSAGES_IN_REVERSE_OPT_NUM = optNum++;
+	var NEWSCAN_ONLY_SHOW_NEW_MSGS_OPT_NUM = optNum++;
+	var USE_INDEXED_MODE_FOR_NEWSCAN_OPT_NUM = optNum++;
+	var INDEX_NEWSCAN_ENTER_SHOWS_MSG_LIST_OPT_NUM = optNum++;
+	var READER_QUIT_TO_MSG_LIST_OPT_NUM = optNum++;
+	var PROPMT_DEL_PERSONAL_MSG_AFTER_REPLY_OPT_NUM = optNum++;
+	var USER_TWITLIST_OPT_NUM = optNum++;
+	var HIGHEST_CHOICE_NUM = USER_TWITLIST_OPT_NUM; // Highest choice number
+	// Specific to personal email
+	var DISPLAY_PERSONAL_MAIL_REPLIED_INDICATOR_CHAR_OPT_NUM = -1;
+	if (this.readingPersonalEmail)
+	{
+		DISPLAY_PERSONAL_MAIL_REPLIED_INDICATOR_CHAR_OPT_NUM = optNum++;
+		HIGHEST_CHOICE_NUM = DISPLAY_PERSONAL_MAIL_REPLIED_INDICATOR_CHAR_OPT_NUM;
+	}
+	// Indexed-mode newscan options (will only be displayed if doing a newscan)
+	var SHOW_INDEXED_NEWSCAN_MENU_IF_NO_NEW_MSGS_OPT_NUM = -1;
+	var INDEXED_MODE_NEWSCAN_MENU_AFTER_READING_ALL_NEW_MSGS_OPT_INDEX = -1;
+	if (this.doingNewscan)
+	{
+		SHOW_INDEXED_NEWSCAN_MENU_IF_NO_NEW_MSGS_OPT_NUM = optNum++;
+		INDEXED_MODE_NEWSCAN_MENU_AFTER_READING_ALL_NEW_MSGS_OPT_INDEX = optNum++;
+		HIGHEST_CHOICE_NUM = INDEXED_MODE_NEWSCAN_MENU_AFTER_READING_ALL_NEW_MSGS_OPT_INDEX;
+	}
 
 	console.crlf();
 	var wordFirstCharAttrs = "\x01c\x01h";
@@ -15166,13 +15261,19 @@ function DigDistMsgReader_DoUserSettings_Traditional()
 	printTradUserSettingOption(LIST_MESSAGES_IN_REVERSE_OPT_NUM, "List messages in reverse", wordFirstCharAttrs, wordRemainingAttrs);
 	printTradUserSettingOption(NEWSCAN_ONLY_SHOW_NEW_MSGS_OPT_NUM, "Only show new messages for newscan", wordFirstCharAttrs, wordRemainingAttrs);
 	printTradUserSettingOption(USE_INDEXED_MODE_FOR_NEWSCAN_OPT_NUM, "Use Indexed mode for newscan", wordFirstCharAttrs, wordRemainingAttrs);
-	printTradUserSettingOption(SHOW_INDEXED_NEWSCAN_MENU_IF_NO_NEW_MSGS_OPT_NUM, "Show indexed menu if there are no new messages", wordFirstCharAttrs, wordRemainingAttrs);
-	printTradUserSettingOption(INDEXED_MODE_NEWSCAN_MENU_AFTER_READING_ALL_NEW_MSGS_OPT_INDEX, "Show indexed menu after reading all new messages", wordFirstCharAttrs, wordRemainingAttrs);
 	printTradUserSettingOption(INDEX_NEWSCAN_ENTER_SHOWS_MSG_LIST_OPT_NUM, "Index: Selection shows message list", wordFirstCharAttrs, wordRemainingAttrs);
 	printTradUserSettingOption(READER_QUIT_TO_MSG_LIST_OPT_NUM, "Quitting From reader goes to message list", wordFirstCharAttrs, wordRemainingAttrs);
 	printTradUserSettingOption(PROPMT_DEL_PERSONAL_MSG_AFTER_REPLY_OPT_NUM, "Prompt to delete personal message after replying", wordFirstCharAttrs, wordRemainingAttrs);
-	printTradUserSettingOption(DISPLAY_PERSONAL_MAIL_REPLIED_INDICATOR_CHAR_OPT_NUM, "Display email replied indicator", wordFirstCharAttrs, wordRemainingAttrs);
 	printTradUserSettingOption(USER_TWITLIST_OPT_NUM, "Personal twit list", wordFirstCharAttrs, wordRemainingAttrs);
+	// Specific to personal email
+	if (this.readingPersonalEmail)
+		printTradUserSettingOption(DISPLAY_PERSONAL_MAIL_REPLIED_INDICATOR_CHAR_OPT_NUM, "Display email replied indicator", wordFirstCharAttrs, wordRemainingAttrs);
+	// Newscan options
+	if (this.doingNewscan)
+	{
+		printTradUserSettingOption(SHOW_INDEXED_NEWSCAN_MENU_IF_NO_NEW_MSGS_OPT_NUM, "Show indexed menu if there are no new messages", wordFirstCharAttrs, wordRemainingAttrs);
+		printTradUserSettingOption(INDEXED_MODE_NEWSCAN_MENU_AFTER_READING_ALL_NEW_MSGS_OPT_INDEX, "Show indexed menu after reading all new messages", wordFirstCharAttrs, wordRemainingAttrs);
+	}
 	console.crlf();
 	console.print("\x01cYour choice (\x01hQ\x01n\x01c: Quit)\x01h: \x01g");
 	var userChoiceNum = console.getnum(HIGHEST_CHOICE_NUM);
@@ -15345,19 +15446,7 @@ function DigDistMsgReader_DoIndexedMode(pScanScope, pNewscanOnly)
 				this.hdrsForCurrentSubBoard = msgHdrsCache[indexRetObj.chosenSubCode].hdrsForCurrentSubBoard;
 				this.msgNumToIdxMap = msgHdrsCache[indexRetObj.chosenSubCode].hdrsForCurrentSubBoardByMsgNum;
 			}
-			// Decide the index of the starting message: If there are no new messages, show the last
-			// messages.  Otherwise, if only showing new messages, show the first messages.
-			// Otherwise, calculate the starting index.
-			var numMessages = this.NumMessages();
-			var startIdx = 0;
-			if (indexRetObj.numNewMsgs == 0)
-				startIdx = numMessages - 1;
-			else if (!this.userSettings.newscanOnlyShowNewMsgs)
-			{
-				startIdx = numMessages > 0 ? numMessages - indexRetObj.numNewMsgs : 0;
-				if (startIdx < 0)
-					startIdx = numMessages - 1;
-			}
+
 			// If the user chose to view the message list, display the message list to let the user
 			// choose a message to read. Otherwise, start reader mode.
 			if (indexRetObj.viewMsgList)
@@ -15385,9 +15474,63 @@ function DigDistMsgReader_DoIndexedMode(pScanScope, pNewscanOnly)
 			else
 			{
 				// Let the user read the sub-board
+				// Decide the index of the starting message: If there are no new messages, show the last
+				// messages.  Otherwise, if only showing new messages, show the first messages.
+				// Otherwise, calculate the starting index.
+				var numMessages = this.NumMessages();
+				var startIdx = 0;
+				if (newscanOnly)
+				{
+					if (indexRetObj.numNewMsgs == 0)
+						startIdx = numMessages - 1;
+					else if (!this.userSettings.newscanOnlyShowNewMsgs)
+					{
+						startIdx = numMessages > 0 ? numMessages - indexRetObj.numNewMsgs : 0;
+						if (startIdx < 0)
+							startIdx = numMessages - 1;
+					}
+				}
+				else
+				{
+					// Not a newscan - Use the last_read pointer
+					var tmpMsgbase = new MsgBase(indexRetObj.chosenSubCode);
+					if (tmpMsgbase.open())
+					{
+						var lastReadMsgHdr = tmpMsgbase.get_msg_index(false, msg_area.sub[indexRetObj.chosenSubCode].last_read, false);
+						if (lastReadMsgHdr != null)
+						{
+							//startIdx = absMsgNumToIdxWithMsgbaseObj(tmpMsgbase, lastReadMsgHdr.number);
+
+							//this.PopulateHdrsForCurrentSubBoard();
+							this.subBoardCode = indexRetObj.chosenSubCode;
+							if (this.hdrsForCurrentSubBoard.length > 0)
+							{
+								startIdx = this.GetMsgIdx(GetScanPtrOrLastMsgNum(this.subBoardCode)) + 1;
+								if (startIdx < 0)
+									startIdx = 0;
+								else if (startIdx >= this.hdrsForCurrentSubBoard.length)
+									startIdx = this.hdrsForCurrentSubBoard.length - 1;
+							}
+						}
+						tmpMsgbase.close();
+					}
+				}
+
 				// pSubBoardCode, pStartingMsgOffset, pReturnOnMessageList, pAllowChgArea, pReturnOnNextAreaNav,
 				// pPromptToGoToNextAreaIfNoSearchResults
 				var readRetObj = this.ReadMessages(indexRetObj.chosenSubCode, startIdx, false, false, true, false);
+				// Even if not doing a newscan, still update the scan pointer to the user's last_read pointer
+				if (!newscanOnly)
+				{
+					if (typeof(msg_area.sub[indexRetObj.chosenSubCode].scan_ptr) === "number")
+					{
+						if (!msgNumIsLatestMsgSpecialVal(msg_area.sub[indexRetObj.chosenSubCode].scan_ptr) && msg_area.sub[indexRetObj.chosenSubCode].scan_ptr < msg_area.sub[indexRetObj.chosenSubCode].last_read)
+							msg_area.sub[indexRetObj.chosenSubCode].scan_ptr = msg_area.sub[indexRetObj.chosenSubCode].last_read;
+					}
+					else
+						msg_area.sub[indexRetObj.chosenSubCode].scan_ptr = msg_area.sub[indexRetObj.chosenSubCode].last_read;
+				}
+
 				// Update the text for the current menu item to ensure the message numbers are up to date
 				var currentMenuItem = this.indexedModeMenu.GetItem(this.indexedModeMenu.selectedItemIdx);
 				var itemInfo = this.GetIndexedModeSubBoardMenuItemTextAndInfo(indexRetObj.chosenSubCode);
@@ -15401,6 +15544,11 @@ function DigDistMsgReader_DoIndexedMode(pScanScope, pNewscanOnly)
 						hdrsForCurrentSubBoardByMsgNum: this.msgNumToIdxMap
 					};
 				}
+				if (!readRetObj.stoppedReading && (readRetObj.lastAction == ACTION_GO_NEXT_MSG_AREA || readRetObj.lastAction == ACTION_GO_NEXT_MSG))
+					this.indexedModeSetIdxMnuIdxOneMore = true;
+				else
+					this.indexedModeSetIdxMnuIdxOneMore = false;
+
 				/*
 				switch (readRetObj.lastAction)
 				{
@@ -15576,7 +15724,19 @@ function DigDistMsgReader_IndexedModeChooseSubBoard(pClearScreen, pDrawMenu, pDi
 		this.indexedModeMenu = this.CreateLightbarIndexedModeMenu(numMsgsWidth, numNewMsgsWidth, lastPostDateWidth, this.indexedModeItemDescWidth, this.indexedModeSubBoardMenuSubBoardFormatStr);
 	}
 	else
+	{
 		DigDistMsgReader_IndexedModeChooseSubBoard.selectedItemIdx = this.indexedModeMenu.selectedItemIdx;
+		/*
+		// Temporary
+		if (user.is_sysop)
+		{
+			console.print("\x01n\r\n");
+			console.print("Indexed menu item index: " + DigDistMsgReader_IndexedModeChooseSubBoard.selectedItemIdx + "\r\n");
+			console.pause();
+		}
+		// End Temporary
+		*/
+	}
 	// Ensure the menu is clear, and (re-)populate the menu with sub-board information w/ # of new messages in each, etc.
 	// Also, build an array of sub-board codes for each menu item.
 	this.indexedModeMenu.RemoveAllItems();
@@ -15676,6 +15836,8 @@ function DigDistMsgReader_IndexedModeChooseSubBoard(pClearScreen, pDrawMenu, pDi
 	if (!thisFunctionFirstCall && typeof(DigDistMsgReader_IndexedModeChooseSubBoard.selectedItemIdx) === "number")
 	{
 		var savedItemIdx = DigDistMsgReader_IndexedModeChooseSubBoard.selectedItemIdx;
+		if (this.indexedModeSetIdxMnuIdxOneMore)
+			++savedItemIdx;
 		if (savedItemIdx >= 0 && savedItemIdx < this.indexedModeMenu.NumItems())
 			setIndexedSubBoardMenuSelectedItemIdx(this.indexedModeMenu, savedItemIdx);
 		else
@@ -23928,6 +24090,69 @@ function entryExistsInTwitList(pStr)
 	return entryExists;
 }
 
+// Adds to the global email filter (email.can).
+//
+// Parameters:
+//  pEmailAddr: An email address
+//
+// Return value: Boolean - Whether or not this was successful
+function addToGlobalEmailFilter(pEmailAddr)
+{
+	if (typeof(pEmailAddr) !== "string")
+		return false;
+
+	var wasSuccessful = true;
+	if (!entryExistsInGlobalEmailFilter(pEmailAddr))
+	{
+		wasSuccessful = false;
+		var filterFile = new File(system.text_dir + "email.can");
+		//if (filterFile.open(filterFile.exists ? "r+" : "w+"))
+		if (filterFile.open("a"))
+		{
+			wasSuccessful = filterFile.writeln(pEmailAddr);
+			filterFile.close();
+		}
+	}
+	return wasSuccessful;
+}
+// Returns whether an entry exists in the global email filter (email.can).
+//
+// Parameters:
+//  pEmailAddr: An entry to check in the twit list
+//
+// Return value: Boolean - Whether or not the given string exists in the twit list
+function entryExistsInGlobalEmailFilter(pEmailAddr)
+{
+	if (typeof(pEmailAddr) !== "string")
+		return false;
+
+	var entryExists = false;
+	var filterFile = new File(system.text_dir + "email.can");
+	if (filterFile.open("r"))
+	{
+		while (!filterFile.eof && !entryExists)
+		{
+			//// Read the next line from the config file.
+			var fileLine = filterFile.readln(2048);
+			// fileLine should be a string, but I've seen some cases
+			// where for some reason it isn't.  If it's not a string,
+			// then continue onto the next line.
+			if (typeof(fileLine) != "string")
+				continue;
+			// If the line starts with with a semicolon (the comment
+			// character) or is blank, then skip it.
+			if ((fileLine.substr(0, 1) == ";") || (fileLine.length == 0))
+				continue;
+
+			// See if this line matches the given string
+			entryExists = (pEmailAddr == skipsp(truncsp(fileLine)));
+		}
+
+		filterFile.close();
+	}
+	return entryExists;
+}
+
 ///////////////////////////////////////////////////////////////////////////////////
 
 // For debugging: Writes some text on the screen at a given location with a given pause.
diff --git a/xtrn/DDMsgReader/ddmr_cfg.js b/xtrn/DDMsgReader/ddmr_cfg.js
index 9abfb64457adcaea50c36173fa4c011e233a832f..a102c96fbb3d99571a02107f65fa8752b46441a9 100644
--- a/xtrn/DDMsgReader/ddmr_cfg.js
+++ b/xtrn/DDMsgReader/ddmr_cfg.js
@@ -5,7 +5,7 @@
 // If you have DDMsgReader in a directory other than xtrn/DDMsgReader, then the changes to
 // DDMsgReader.cfg will be saved in that directory (assuming you're running ddmr_cfg.js from
 // that same directory).
-// Currently for DDMsgReader 1.93.
+// Currently for DDMsgReader 1.94.
 //
 // If you're running DDMsgReader from xtrn/DDMsgReader (the standard location) and you want
 // to save the configuration file there (rather than sbbs/mods), you can use one of the
@@ -18,7 +18,7 @@ require("sbbsdefs.js", "P_NONE");
 require("uifcdefs.js", "UIFC_INMSG");
 
 
-if (!uifc.init("DigDist. Message Reader 1.93 Configurator"))
+if (!uifc.init("DigDist. Message Reader 1.94 Configurator"))
 {
 	print("Failed to initialize uifc");
 	exit(1);
diff --git a/xtrn/DDMsgReader/readme.txt b/xtrn/DDMsgReader/readme.txt
index f8a052871f0d223026f0d3cabaa98c548b88c29e..2c29a2b29213bd6c1fa9f49d3011ad73b37f53da 100644
--- a/xtrn/DDMsgReader/readme.txt
+++ b/xtrn/DDMsgReader/readme.txt
@@ -1,6 +1,6 @@
                       Digital Distortion Message Reader
-                                 Version 1.93
-                           Release date: 2024-01-01
+                                 Version 1.94
+                           Release date: 2024-01-08
 
                                      by
 
@@ -312,6 +312,8 @@ The following are the command-line parameters supported by DDMsgReader.js:
               user wants to list sub-boards in the current group, or all
               sub-boards.
               This is intended to work if it is the only command-line option.
+-indexModeScope: Specifies the scope (set of sub-boards) for indexed reader mode
+                 with -indexedMode. Valid values are "group" or "all".
 -search: A search type.  Available options:
  keyword_search: Do a keyword search in message subject/body text (current message area)
  from_name_search: 'From' name search (current message area)
@@ -452,6 +454,14 @@ common message operations.
 - Start in indexed reader mode:
 ?../xtrn/DDMsgReader/DDMsgReader.js -indexedMode
 
+- Start in indexed reader mode for the sub-boards in the current group (without
+prompting):
+?../xtrn/DDMsgReader/DDMsgReader.js -indexedMode -indexModeScope=group
+
+- Start in indexed reader mode for all sub-boards(without prompting):
+?../xtrn/DDMsgReader/DDMsgReader.js -indexedMode -indexModeScope=all
+
+
 - Text (keyword) search in the current sub-board, and list the messages found:
 ?../xtrn/DDMsgReader/DDMsgReader.js -search=keyword_search -startMode=list
 
@@ -1248,11 +1258,15 @@ Indexed reader mode may also be started with the -indexedMode command-line
 parameter.  For example, if you are using a JavaScript command shell:
   bbs.exec("?../xtrn/DDMsgReader/DDMsgReader.js -indexedMode");
 With the above command-line parameter, DDMsgReader will show all sub-boards the
-user is allowed to read and which they have in their newscan configuration.
-If the user has enabled indexed mode for newscans, then during a newscan, it
-will show sub-boards based on the user's chosen option for current
-sub-board/group/all.
-  
+user is allowed to read.  It will prompt the user to use sub-boards in the
+current group or all sub-boards.
+
+To have it start in indexed reader for the current group without prompting:
+bbs.exec("?../xtrn/DDMsgReader/DDMsgReader.js -indexedMode -indexModeScope=group");
+
+To have it start in indexed reader for all sub-boards without prompting:
+bbs.exec("?../xtrn/DDMsgReader/DDMsgReader.js -indexedMode -indexModeScope=all");
+
 This is an example of the sub-board menu that appears in indexed mode - And from
 here, the user can choose a sub-board to read:
 
diff --git a/xtrn/DDMsgReader/revision_history.txt b/xtrn/DDMsgReader/revision_history.txt
index 54e88305f8750ce0834401e8fa6e9fb90afd3c5a..b4d061f9c2b3261ce76a0533c7e19d6dda49524b 100644
--- a/xtrn/DDMsgReader/revision_history.txt
+++ b/xtrn/DDMsgReader/revision_history.txt
@@ -5,6 +5,17 @@ Revision History (change log)
 =============================
 Version  Date         Description
 -------  ----         -----------
+1.94     2024-01-07   Fix: For indexed read mode (not doing a newscan), when
+                      choosing a sub-board to read, the correct (first unread)
+                      message is displayed. Also, the user's scan pointer is
+                      also updated to the last_read pointer.
+                      New operator option for read mode: Add author email to
+                      email.can
+                      New command-line option: -indexModeScope, which can
+                      specify the indexed reader scope (group/all) without
+                      prompting the user.
+                      User configuration options for newscan & email only shown
+                      when doing those actions
 1.93     2024-01-01   New user-toggleable behavior: Show indexed menu after
                       reading all new messages
                       Also, indexed reader mode (started with the -indexedMode