Skip to content
Snippets Groups Projects
DDMsgReader.js 714 KiB
Newer Older
						this.WriteMsgGroupLine(selectedGrpIndex, false);
					}
					selectedGrpIndex = previousGrpIndex;
				}
				break;
			case KEY_DOWN: // Move down one message group in the list
				if (selectedGrpIndex < msg_area.grp_list.length - 1)
				{
					// If the next group index is on the next page, then display
					// the next page.
					var nextGrpIndex = selectedGrpIndex + 1;
					if (nextGrpIndex > bottomMsgGrpIndex)
					{
						// Adjust topMsgGrpIndex and bottomMsgGrpIndex, and
						// refresh the list on the screen.
						topMsgGrpIndex += numItemsPerPage;
						bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage);
						this.UpdateMsgAreaPageNumInHeader(pageNum+1, numPages, true, false);
						this.ListScreenfulOfMsgGrps(topMsgGrpIndex, listStartRow,
						                            listEndRow, false, true);
					}
					else
					{
						// Display the current line un-highlighted.
						console.gotoxy(1, curpos.y);
						this.WriteMsgGroupLine(selectedGrpIndex, false);
					}
					selectedGrpIndex = nextGrpIndex;
				}
				break;
			case KEY_HOME: // Go to the top message group on the screen
				if (selectedGrpIndex > topMsgGrpIndex)
				{
					// Display the current line un-highlighted, then adjust
					// selectedGrpIndex.
					console.gotoxy(1, curpos.y);
					this.WriteMsgGroupLine(selectedGrpIndex, false);
					selectedGrpIndex = topMsgGrpIndex;
					// Note: curpos.y is set at the start of the while loop.
				}
				break;
			case KEY_END: // Go to the bottom message group on the screen
				if (selectedGrpIndex < bottomMsgGrpIndex)
				{
					// Display the current line un-highlighted, then adjust
					// selectedGrpIndex.
					console.gotoxy(1, curpos.y);
					this.WriteMsgGroupLine(selectedGrpIndex, false);
					selectedGrpIndex = bottomMsgGrpIndex;
					// Note: curpos.y is set at the start of the while loop.
				}
				break;
			case KEY_ENTER: // Select the currently-highlighted message group
				retObj = this.SelectSubBoard_Lightbar(selectedGrpIndex);
				// If the user chose a sub-board, then set bbs.curgrp and
				// bbs.cursub, and don't continue the input loop anymore.
				if (retObj.subBoardChosen)
				{
					bbs.curgrp = selectedGrpIndex;
					bbs.cursub = retObj.subBoardIndex;
					continueChoosingMsgArea = false;
				}
				else
				{
					// A sub-board was not chosen, so we'll have to re-draw
					// the header and list of message groups.
nightfox's avatar
nightfox committed
					console.gotoxy(1, this.areaChangeHdrLines.length+1);
					this.WriteGrpListHdrLine(numPages, pageNum);
					this.ListScreenfulOfMsgGrps(topMsgGrpIndex, listStartRow, listEndRow,
					                            false, true);
				}
				break;
			case KEY_PAGE_DOWN: // Go to the next page
			case 'N': // Go to the next page
				var nextPageTopIndex = topMsgGrpIndex + numItemsPerPage;
				if (nextPageTopIndex < msg_area.grp_list.length)
				{
					// Adjust topMsgGrpIndex and bottomMsgGrpIndex, and
					// refresh the list on the screen.
					topMsgGrpIndex = nextPageTopIndex;
					pageNum = calcPageNum(topMsgGrpIndex, numItemsPerPage);
					bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage);
					this.UpdateMsgAreaPageNumInHeader(pageNum, numPages, true, false);
					this.ListScreenfulOfMsgGrps(topMsgGrpIndex, listStartRow,
					                            listEndRow, false, true);
					selectedGrpIndex = topMsgGrpIndex;
				}
				break;
			case KEY_PAGE_UP: // Go to the previous page
			case 'P': // Go to the previous page
				var prevPageTopIndex = topMsgGrpIndex - numItemsPerPage;
				if (prevPageTopIndex >= 0)
				{
					// Adjust topMsgGrpIndex and bottomMsgGrpIndex, and
					// refresh the list on the screen.
					topMsgGrpIndex = prevPageTopIndex;
					pageNum = calcPageNum(topMsgGrpIndex, numItemsPerPage);
					bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage);
					this.UpdateMsgAreaPageNumInHeader(pageNum, numPages, true, false);
					this.ListScreenfulOfMsgGrps(topMsgGrpIndex, listStartRow,
					                            listEndRow, false, true);
					selectedGrpIndex = topMsgGrpIndex;
				}
				break;
			case 'F': // Go to the first page
				if (topMsgGrpIndex > 0)
				{
					topMsgGrpIndex = 0;
					pageNum = calcPageNum(topMsgGrpIndex, numItemsPerPage);
					bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage);
					this.UpdateMsgAreaPageNumInHeader(pageNum, numPages, true, false);
					this.ListScreenfulOfMsgGrps(topMsgGrpIndex, listStartRow, listEndRow,
					                            false, true);
					selectedGrpIndex = 0;
				}
				break;
			case 'L': // Go to the last page
				if (topMsgGrpIndex < topIndexForLastPage)
				{
					topMsgGrpIndex = topIndexForLastPage;
					pageNum = calcPageNum(topMsgGrpIndex, numItemsPerPage);
					bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage);
					this.UpdateMsgAreaPageNumInHeader(pageNum, numPages, true, false);
					this.ListScreenfulOfMsgGrps(topMsgGrpIndex, listStartRow, listEndRow,
					                            false, true);
					selectedGrpIndex = topIndexForLastPage;
				}
				break;
			case 'Q': // Quit
				continueChoosingMsgArea = false;
				break;
			case '?': // Show help
				this.ShowChooseMsgAreaHelpScreen(true, true);
				console.pause();
				// Refresh the screen
				this.WriteChgMsgAreaKeysHelpLine();
				this.DisplayAreaChgHdr(1);
				console.gotoxy(1, 1+this.areaChangeHdrLines.length);
				this.WriteGrpListHdrLine(numPages, pageNum);
				this.ListScreenfulOfMsgGrps(topMsgGrpIndex, listStartRow, listEndRow,
				                            false, true);
				break;
			default:
				// If the user entered a numeric digit, then treat it as
				// the start of the message group number.
				if (userInput.match(/[0-9]/))
				{
					var originalCurpos = curpos;

					// Put the user's input back in the input buffer to
					// be used for getting the rest of the message number.
					console.ungetstr(userInput);
					// Move the cursor to the bottom of the screen and
					// prompt the user for the message number.
					console.gotoxy(1, console.screen_rows);
					console.clearline("\1n");
					console.print("\1cChoose group #: \1h");
					userInput = console.getnum(msg_area.grp_list.length);
					// If the user made a selection, then let them choose a
					// sub-board from the group.
					if (userInput > 0)
					{
						var msgGroupIndex = userInput - 1;
						retObj = this.SelectSubBoard_Lightbar(msgGroupIndex);
						// If the user chose a sub-board, then set bbs.curgrp and
						// bbs.cursub, and don't continue the input loop anymore.
						if (retObj.subBoardChosen)
						{
							// Set the current group & sub-board
							bbs.curgrp = msgGroupIndex;
							bbs.cursub = retObj.subBoardIndex;
							continueChoosingMsgArea = false;
						}
						else
						{
							// A sub-board was not chosen, so we'll have to re-draw
							// the header and list of message groups.
							console.gotoxy(1, 1);
							this.WriteGrpListHdrLine(numPages, pageNum);
							this.ListScreenfulOfMsgGrps(topMsgGrpIndex, listStartRow, listEndRow,
							                            false, true);
						}
					}
					else
					{
						// The user didn't make a selection.  So, we need to refresh
						// the screen due to everything being moved up one line.
						this.WriteChgMsgAreaKeysHelpLine();
						console.gotoxy(1, 1);
						this.WriteGrpListHdrLine(numPages, pageNum);
						this.ListScreenfulOfMsgGrps(topMsgGrpIndex, listStartRow, listEndRow,
						                            false, true);
					}
				}
				break;
		}
	}

	// If the user chose a different message group & sub-board, then reset the
	// lister index & cursor variables, as well as this.subBoardCode, etc.
	if ((bbs.curgrp != oldGrp) || (bbs.cursub != oldSub))
	{
		this.tradListTopMsgIdx = -1;
		this.lightbarListTopMsgIdx = -1;
		this.lightbarListSelectedMsgIdx = -1;
		this.lightbarListCurPos = null;
		this.setSubBoardCode(msg_area.grp_list[bbs.curgrp].sub_list[bbs.cursub].code);
		// Re-create the msgbase object for the new sub-board.  Don't open it yet,
		// as that is done in the read/list methods.
		if (this.msgbase != null)
		{
			if (this.msgbase.is_open)
				this.msgbase.close();
			this.msgbase = null;
		}
		this.msgbase = new MsgBase(this.subBoardCode);
	}
}

// For the DigDistMsgReader class: Lets the user choose a sub-board within a
// message group, with a lightbar interface.  Does not set bbs.cursub.
//
// Parameters:
//  pGrpIndex: The index of the message group to choose from.  This is
//             optional; if not specified, bbs.curgrp will be used.
//  pMarkIndex: An index of a message group to display the "current" mark
//              next to.  This is optional; if left off, this will default to
//              the current sub-board.
//
// Return value: An object containing the following values:
//               subBoardChosen: Boolean - Whether or not a sub-board was chosen.
//               subBoardIndex: Numeric - The sub-board that was chosen (if any).
//                              Will be -1 if none chosen.
function DigDistMsgReader_SelectSubBoard_Lightbar(pGrpIndex, pMarkIndex)
nightfox's avatar
nightfox committed
	// Create the return object.
	var retObj = new Object();
	retObj.subBoardChosen = false;
	retObj.subBoardIndex = -1;
nightfox's avatar
nightfox committed
	var grpIndex = 0;
	if (typeof(pGrpIndex) == "number")
		grpIndex = pGrpIndex;
	else
		grpIndex = msg_area.sub[this.subBoardCode].grp_index;
	// Older:
	/*
	else if ((bbs.curgrp != null) && (typeof(bbs.curgrp) == "number"))
		grpIndex = bbs.curgrp;
	*/
	// Double-check grpIndex
	if (grpIndex < 0)
		grpIndex = 0;
	else if (grpIndex >= msg_area.grp_list.length)
		grpIndex = msg_area.grp_list.length - 1;
nightfox's avatar
nightfox committed
	var markIndex = 0;
	if ((pMarkIndex != null) && (typeof(pMarkIndex) == "number"))
		markIndex = pMarkIndex;
	else
		markIndex = msg_area.sub[this.subBoardCode].index;
	// Older:
	/*
	else if ((bbs.cursub != null) && (typeof(bbs.cursub) == "number") &&
				(bbs.curgrp == pGrpIndex))
	{
		markIndex = bbs.cursub;
	}
	*/
	// Double-check markIndex
	if (markIndex < 0)
		markIndex = 0;
	else if (markIndex >= msg_area.grp_list[grpIndex].sub_list.length)
		markIndex = msg_area.grp_list[grpIndex].sub_list.length - 1;
nightfox's avatar
nightfox committed
	// Ensure that the sub-board printf information is created for
	// this message group.
	this.BuildSubBoardPrintfInfoForGrp(grpIndex);
nightfox's avatar
nightfox committed
	// If there are no sub-boards in the given message group, then show
	// an error and return.
	if (msg_area.grp_list[grpIndex].sub_list.length == 0)
	{
		console.clear("\1n");
		console.print("\1y\1hThere are no sub-boards in the chosen group.\r\n\1p");
		return retObj;
	}
nightfox's avatar
nightfox committed
	// Returns the index of the bottommost sub-board that can be displayed on
	// the screen.
	//
	// Parameters:
	//  pTopSubIndex: The index of the topmost sub-board displayed on screen
	//  pNumItemsPerPage: The number of items per page
	function getBottommostSubIndex(pTopSubIndex, pNumItemsPerPage)
	{
		var bottomGrpIndex = topSubIndex + pNumItemsPerPage - 1;
		// If bottomGrpIndex is beyond the last index, then adjust it.
		if (bottomGrpIndex >= msg_area.grp_list[grpIndex].sub_list.length)
			bottomGrpIndex = msg_area.grp_list[grpIndex].sub_list.length - 1;
		return bottomGrpIndex;
	}
nightfox's avatar
nightfox committed
	// Figure out the index of the user's currently-selected sub-board.
	var selectedSubIndex = 0;
	if (msg_area.sub[this.subBoardCode].grp_index == pGrpIndex)
		selectedSubIndex = msg_area.sub[this.subBoardCode].index;
	/*
	var selectedSubIndex = 0;
	if ((bbs.cursub != null) && (typeof(bbs.cursub) == "number"))
	{
		if ((bbs.curgrp != null) && (typeof(bbs.curgrp) == "number") &&
			(bbs.curgrp == pGrpIndex))
		{
			selectedSubIndex = bbs.cursub;
		}
	}
	*/
nightfox's avatar
nightfox committed
	// listStartRow is the row on the screen where the list will start
	var listStartRow = 3 + this.areaChangeHdrLines.length;
	var listEndRow = console.screen_rows - 1; // Row on screen where list will end
	var topSubIndex = 0;      // The index of the message group at the top of the list
	// Figure out the index of the last message group to appear on the screen.
	var numItemsPerPage = listEndRow - listStartRow + 1;
	var bottomSubIndex = getBottommostSubIndex(topSubIndex, numItemsPerPage);
	// Figure out how many pages are needed to list all the sub-boards.
	var numPages = Math.ceil(msg_area.grp_list[grpIndex].sub_list.length / numItemsPerPage);
	// Figure out the top index for the last page.
	var topIndexForLastPage = (numItemsPerPage * numPages) - numItemsPerPage;
nightfox's avatar
nightfox committed
	// If the highlighted row is beyond the current screen, then
	// go to the appropriate page.
	if (selectedSubIndex > bottomSubIndex)
	{
		var nextPageTopIndex = 0;
		while (selectedSubIndex > bottomSubIndex)
		{
			nextPageTopIndex = topSubIndex + numItemsPerPage;
			if (nextPageTopIndex < msg_area.grp_list[grpIndex].sub_list.length)
			{
				// Adjust topSubIndex and bottomSubIndex, and
				// refresh the list on the screen.
				topSubIndex = nextPageTopIndex;
				bottomSubIndex = getBottommostSubIndex(topSubIndex, numItemsPerPage);
			}
			else
				break;
		}

		// If we didn't find the correct page for some reason, then set the
		// variables to display page 1 and select the first message group.
		var foundCorrectPage =
		         ((topSubIndex < msg_area.grp_list[grpIndex].sub_list.length) &&
		         (selectedSubIndex >= topSubIndex) && (selectedSubIndex <= bottomSubIndex));
		if (!foundCorrectPage)
		{
			topSubIndex = 0;
			bottomSubIndex = getBottommostSubIndex(topSubIndex, numItemsPerPage);
			selectedSubIndex = 0;
		}
	}

	// Clear the screen, write the header line, help line and group list header,
	// and output a screenful of message sub-boards.
	console.clear("\1n");
	this.DisplayAreaChgHdr(1);
	if (this.areaChangeHdrLines.length > 0)
		console.crlf();
	var pageNum = calcPageNum(topSubIndex, numItemsPerPage);
	this.WriteSubBrdListHdr1Line(grpIndex, numPages, pageNum);
	this.WriteChgMsgAreaKeysHelpLine();

	var curpos = new Object();
	curpos.x = 1;
	curpos.y = 2 + this.areaChangeHdrLines.length;
	console.gotoxy(curpos);
	printf(this.subBoardListHdrPrintfStr, "Sub #", "Name", "# Posts", "Latest date & time");
	this.ListScreenfulOfSubBrds(grpIndex, topSubIndex, listStartRow, listEndRow, false, false);
	// Start of the input loop.
	var highlightScrenRow = 0; // The row on the screen for the highlighted group
	var userInput = "";        // Will store a keypress from the user
	var continueChoosingSubBrd = true;
	while (continueChoosingSubBrd)
	{
		// Highlight the currently-selected message group
		highlightScrenRow = listStartRow + (selectedSubIndex - topSubIndex);
		curpos.y = highlightScrenRow;
		if ((highlightScrenRow > 0) && (highlightScrenRow < console.screen_rows))
		{
			console.gotoxy(1, highlightScrenRow);
			this.WriteMsgSubBoardLine(grpIndex, selectedSubIndex, true);
		}

		// Get a key from the user (upper-case) and take action based upon it.
		//userInput = console.getkey(K_UPPER | K_NOCRLF);
		userInput = getKeyWithESCChars(K_UPPER | K_NOCRLF);
		switch (userInput)
		{
			case KEY_UP: // Move up one message group in the list
				if (selectedSubIndex > 0)
				{
					// If the previous group index is on the previous page, then
					// display the previous page.
					var previousSubIndex = selectedSubIndex - 1;
					if (previousSubIndex < topSubIndex)
					{
						// Adjust topSubIndex and bottomSubIndex, and
						// refresh the list on the screen.
						topSubIndex -= numItemsPerPage;
						bottomSubIndex = getBottommostSubIndex(topSubIndex, numItemsPerPage);
						pageNum = calcPageNum(topSubIndex, numItemsPerPage);
						this.UpdateMsgAreaPageNumInHeader(pageNum, numPages, false, false);
						this.ListScreenfulOfSubBrds(grpIndex, topSubIndex, listStartRow, listEndRow, false, true);
					}
					else
					{
						// Display the current line un-highlighted.
						console.gotoxy(1, curpos.y);
						this.WriteMsgSubBoardLine(grpIndex, selectedSubIndex, false);
					}
					selectedSubIndex = previousSubIndex;
				}
				break;
			case KEY_DOWN: // Move down one message group in the list
				if (selectedSubIndex < msg_area.grp_list[grpIndex].sub_list.length - 1)
				{
					// If the next group index is on the next page, then display
					// the next page.
					var nextGrpIndex = selectedSubIndex + 1;
					if (nextGrpIndex > bottomSubIndex)
					{
						// Adjust topSubIndex and bottomSubIndex, and
						// refresh the list on the screen.
						topSubIndex += numItemsPerPage;
						bottomSubIndex = getBottommostSubIndex(topSubIndex, numItemsPerPage);
						pageNum = calcPageNum(topSubIndex, numItemsPerPage);
						this.UpdateMsgAreaPageNumInHeader(pageNum, numPages, false, false);
						this.ListScreenfulOfSubBrds(grpIndex, topSubIndex, listStartRow, listEndRow, false, true);
					}
					else
					{
						// Display the current line un-highlighted.
						console.gotoxy(1, curpos.y);
						this.WriteMsgSubBoardLine(grpIndex, selectedSubIndex, false);
					}
					selectedSubIndex = nextGrpIndex;
				}
				break;
			case KEY_HOME: // Go to the top message group on the screen
				if (selectedSubIndex > topSubIndex)
				{
					// Display the current line un-highlighted, then adjust
					// selectedSubIndex.
					console.gotoxy(1, curpos.y);
					this.WriteMsgSubBoardLine(grpIndex, selectedSubIndex, false);
					selectedSubIndex = topSubIndex;
					// Note: curpos.y is set at the start of the while loop.
				}
				break;
			case KEY_END: // Go to the bottom message group on the screen
				if (selectedSubIndex < bottomSubIndex)
				{
					// Display the current line un-highlighted, then adjust
					// selectedSubIndex.
					console.gotoxy(1, curpos.y);
					this.WriteMsgSubBoardLine(grpIndex, selectedSubIndex, false);
					selectedSubIndex = bottomSubIndex;
					// Note: curpos.y is set at the start of the while loop.
				}
				break;
			case KEY_ENTER: // Select the currently-highlighted sub-board
				// Validate the sub-board choice.  If a search is specified, the
				// validator function will search for messages in the selected
				// sub-board and will return true if there are messages to read
				// there or false if not.  If there is no search specified,
				// the validator function will return a 'true' value.
				var msgAreaValidRetval = this.ValidateMsgAreaChoice(grpIndex, selectedSubIndex, curpos);
				if (msgAreaValidRetval.msgAreaGood)
				{
					continueChoosingSubBrd = false;
					retObj.subBoardChosen = true;
					retObj.subBoardIndex = selectedSubIndex;
				}
				else
				{
					// Output the error that was returned by the validator function
					console.gotoxy(1, curpos.y);
					console.cleartoeol("\1n");
					console.print("\1h\1y" + msgAreaValidRetval.errorMsg);
					mswait(ERROR_PAUSE_WAIT_MS);
					console.print("\1n");
					continueChoosingSubBrd = true;
					retObj.subBoardChosen = false;
					retObj.subBoardIndex = -1;
				}
nightfox's avatar
nightfox committed
				break;
			case KEY_PAGE_DOWN: // Go to the next page
			case 'N':
				var nextPageTopIndex = topSubIndex + numItemsPerPage;
				if (nextPageTopIndex < msg_area.grp_list[grpIndex].sub_list.length)
				{
					// Adjust topSubIndex and bottomSubIndex, and
					// refresh the list on the screen.
					topSubIndex = nextPageTopIndex;
					pageNum = calcPageNum(topSubIndex, numItemsPerPage);
					bottomSubIndex = getBottommostSubIndex(topSubIndex, numItemsPerPage);
					this.UpdateMsgAreaPageNumInHeader(pageNum, numPages, false, false);
					this.ListScreenfulOfSubBrds(grpIndex, topSubIndex, listStartRow, listEndRow, false, true);
					selectedSubIndex = topSubIndex;
				}
				break;
			case KEY_PAGE_UP: // Go to the previous page
			case 'P':
				var prevPageTopIndex = topSubIndex - numItemsPerPage;
				if (prevPageTopIndex >= 0)
				{
					// Adjust topSubIndex and bottomSubIndex, and
					// refresh the list on the screen.
					topSubIndex = prevPageTopIndex;
					pageNum = calcPageNum(topSubIndex, numItemsPerPage);
					bottomSubIndex = getBottommostSubIndex(topSubIndex, numItemsPerPage);
					this.UpdateMsgAreaPageNumInHeader(pageNum, numPages, false, false);
					this.ListScreenfulOfSubBrds(grpIndex, topSubIndex, listStartRow, listEndRow, false, true);
					selectedSubIndex = topSubIndex;
				}
				break;
			case 'F': // Go to the first page
				if (topSubIndex > 0)
				{
					topSubIndex = 0;
					pageNum = calcPageNum(topSubIndex, numItemsPerPage);
					bottomSubIndex = getBottommostSubIndex(topSubIndex, numItemsPerPage);
					this.UpdateMsgAreaPageNumInHeader(pageNum, numPages, false, false);
					this.ListScreenfulOfSubBrds(grpIndex, topSubIndex, listStartRow, listEndRow, false, true);
					selectedSubIndex = 0;
				}
				break;
			case 'L': // Go to the last page
				if (topSubIndex < topIndexForLastPage)
				{
					topSubIndex = topIndexForLastPage;
					pageNum = calcPageNum(topSubIndex, numItemsPerPage);
					bottomSubIndex = getBottommostSubIndex(topSubIndex, numItemsPerPage);
					this.UpdateMsgAreaPageNumInHeader(pageNum, numPages, false, false);
					this.ListScreenfulOfSubBrds(grpIndex, topSubIndex, listStartRow, listEndRow, false, true);
					selectedSubIndex = topIndexForLastPage;
				}
				break;
			case 'Q': // Quit
				continueChoosingSubBrd = false;
				break;
			case '?': // Show help
				this.ShowChooseMsgAreaHelpScreen(true, true);
				console.pause();
				// Refresh the screen
				this.DisplayAreaChgHdr(1);
				//if (this.areaChangeHdrLines.length > 0)
				//	console.crlf();
				console.gotoxy(1, 1+this.areaChangeHdrLines.length);
nightfox's avatar
nightfox committed
				this.WriteSubBrdListHdr1Line(grpIndex, numPages, pageNum);
				console.cleartoeol("\1n");
				this.WriteChgMsgAreaKeysHelpLine();
				console.gotoxy(1, 2+this.areaChangeHdrLines.length);
nightfox's avatar
nightfox committed
				printf(this.subBoardListHdrPrintfStr, "Sub #", "Name", "# Posts", "Latest date & time");
				this.ListScreenfulOfSubBrds(grpIndex, topSubIndex, listStartRow, listEndRow, false, true);
				break;
			default:
				// If the user entered a numeric digit, then treat it as
				// the start of the message sub-board number.
				if (userInput.match(/[0-9]/))
				{
					var originalCurpos = curpos;

					// Put the user's input back in the input buffer to
					// be used for getting the rest of the message number.
					console.ungetstr(userInput);
					// Move the cursor to the bottom of the screen and
					// prompt the user for the message number.
					console.gotoxy(1, console.screen_rows);
					console.clearline("\1n");
					console.print("\1cSub-board #: \1h");
					userInput = console.getnum(msg_area.grp_list[grpIndex].sub_list.length);
					// If the user made a selection, then set it in the
					// return object and don't continue the input loop.
					if (userInput > 0)
					{
						// Validate the sub-board choice.  If a search is specified, the
						// validator function will search for messages in the selected
						// sub-board and will return true if there are messages to read
						// there or false if not.  If there is no search specified,
						// the validator function will return a 'true' value.
						var msgAreaValidRetval = this.ValidateMsgAreaChoice(grpIndex, selectedSubIndex, curpos);
						if (msgAreaValidRetval.msgAreaGood)
						{
							continueChoosingSubBrd = false;
							retObj.subBoardChosen = true;
							retObj.subBoardIndex = userInput - 1;
						}
						else
						{
							// Output the error that was returned by the validator function
							console.print("\1n\1y\1h" + msgAreaValidRetval.errorMsg);
							mswait(ERROR_PAUSE_WAIT_MS);
							// Set our loop variables so that we continue the sub-board
							// choosing loop.
							continueChoosingSubBrd = true;
							retObj.subBoardChosen = false;
							retObj.subBoardIndex = -1;
							// Since the message area selection failed, we need to
							// re-draw the screen due to everything being moved up one
							// line.
							console.gotoxy(1, 1);
nightfox's avatar
nightfox committed
							this.DisplayAreaChgHdr(1);
							if (this.areaChangeHdrLines.length > 0)
								console.crlf();
							this.WriteSubBrdListHdr1Line(grpIndex, numPages, pageNum);
							console.cleartoeol("\1n");
							this.WriteChgMsgAreaKeysHelpLine();
							console.gotoxy(1, 2);
nightfox's avatar
nightfox committed
							printf(this.subBoardListHdrPrintfStr, "Sub #", "Name", "# Posts", "Latest date & time");
							this.ListScreenfulOfSubBrds(grpIndex, topSubIndex, listStartRow, listEndRow, false, true);
nightfox's avatar
nightfox committed
					}
					else
					{
						// The user didn't enter a selection.  Now we need to re-draw
						// the screen due to everything being moved up one line.
						console.gotoxy(1, 1);
						this.DisplayAreaChgHdr(1);
						if (this.areaChangeHdrLines.length > 0)
							console.crlf();
						this.WriteSubBrdListHdr1Line(grpIndex, numPages, pageNum);
						console.cleartoeol("\1n");
						this.WriteChgMsgAreaKeysHelpLine();
						console.gotoxy(1, 2);
						printf(this.subBoardListHdrPrintfStr, "Sub #", "Name", "# Posts", "Latest date & time");
						this.ListScreenfulOfSubBrds(grpIndex, topSubIndex, listStartRow, listEndRow, false, true);
					}
				}
				break;
		}
	}
nightfox's avatar
nightfox committed
	return retObj;
}

// For the DigDistMsgReader class: Lets the user choose a message group and
// sub-board via numeric input, using a traditional user interface.
function DigDistMsgReader_SelectMsgArea_Traditional()
	// If there are no message groups, then don't let the user
	// choose one.
	if (msg_area.grp_list.length == 0)
	{
		console.clear("\1n");
		console.print("\1y\1hThere are no message groups.\r\n\1p");
		return;
	}
	// Make a backup of the current message group & sub-board indexes so
	// that later we can tell if the user chose something different.
	var oldGrp = msg_area.sub[this.subBoardCode].grp_index;
	var oldSub = msg_area.sub[this.subBoardCode].index;
	// Older:
	/*
	var oldGrp = bbs.curgrp;
	var oldSub = bbs.cursub;
	*/
	// Show the message groups & sub-boards and let the user choose one.
	var selectedGrp = 0;      // The user's selected message group
	var selectedSubBoard = 0; // The user's selected sub-board
	var continueChoosingMsgGroup = true;
	while (continueChoosingMsgGroup)
	{
		// Clear the BBS command string to make sure there are no extra
		// commands in there that could cause weird things to happen.
		bbs.command_str = "";
nightfox's avatar
nightfox committed
		this.DisplayAreaChgHdr();
		//console.crlf();
		this.ListMsgGrps();
		console.crlf();
		console.print("\1n\1b\1hþ \1n\1cWhich, \1hQ\1n\1cuit, or [\1h" +
		              +(msg_area.sub[this.subBoardCode].grp_index+1) + "\1n\1c]: \1h");
		// Older:
		/*
		console.print("\1n\1b\1hþ \1n\1cWhich, \1hQ\1n\1cuit, or [\1h" +
                      +(bbs.curgrp+1) + "\1n\1c]: \1h");
		*/
		// Accept Q (quit) or a file library number
		selectedGrp = console.getkeys("Q", msg_area.grp_list.length);

		// If the user just pressed enter (selectedGrp would be blank),
		// default to the current group.
		if (selectedGrp.toString() == "")
		selectedGrp = msg_area.sub[this.subBoardCode].grp_index + 1;
		// Older:
		/*
		if (selectedGrp.toString() == "")
			selectedGrp = bbs.curgrp + 1;
		*/

		if (selectedGrp.toString() == "Q")
			continueChoosingMsgGroup = false;
		else
		{
			// If the user specified a message group number, then
			// set it and let the user choose a sub-board within
			// the group.
			if (selectedGrp > 0)
			{
				// Set the default sub-board #: The current sub-board, or if the
				// user chose a different group, then this should be set
				// to the first sub-board.
				var defaultSubBoard = msg_area.sub[this.subBoardCode].index + 1;
				if (selectedGrp-1 != msg_area.sub[this.subBoardCode].grp_index)
					defaultSubBoard = 1;
				// Older:
				/*
				var defaultSubBoard = bbs.cursub + 1;
				if (selectedGrp-1 != bbs.curgrp)
					defaultSubBoard = 1;
				*/

				var continueChoosingSubBoard = true;
				while (continueChoosingSubBoard)
				{
					console.clear("\1n");
nightfox's avatar
nightfox committed
					this.DisplayAreaChgHdr();
					this.ListSubBoardsInMsgGroup(selectedGrp-1, defaultSubBoard-1);
					console.crlf();
					console.print("\1n\1b\1hþ \1n\1cWhich, \1hQ\1n\1cuit, or [\1h" +
					// Accept Q (quit) or a sub-board number
					selectedSubBoard = console.getkeys("Q", msg_area.grp_list[selectedGrp - 1].sub_list.length);

					// If the user just pressed enter (selectedSubBoard would be blank),
					// default the selected directory.
					if (selectedSubBoard.toString() == "")
						selectedSubBoard = defaultSubBoard;

					// If the user chose to quit out of the sub-board list, then
					// return to the message group list.
					if (selectedSubBoard.toString() == "Q")
						continueChoosingSubBoard = false;
					// If the user chose a message sub-board, then validate the user's
					// sub-board choice; if that succeeds, then change the user's
					// sub-board to that and quit out of the chooser loops.
					else if (selectedSubBoard > 0)
					{
						// Validate the sub-board choice.  If a search is specified, the
						// validator function will search for messages in the selected
						// sub-board and will return true if there are messages to read
						// there or false if not.  If there is no search specified,
						// the validator function will return a 'true' value.
						var selectedGrpIdx = selectedGrp - 1;
						var selectedSubIdx = selectedSubBoard - 1;
						var msgAreaValidRetval = this.ValidateMsgAreaChoice(selectedGrpIdx, selectedSubIdx);
						if (msgAreaValidRetval.msgAreaGood)
						{
							bbs.curgrp = selectedGrpIdx;
							bbs.cursub = selectedSubIdx;
							continueChoosingSubBoard = false;
							continueChoosingMsgGroup = false;
						}
						else
						{
							// Output the error returned by the validator function
							console.print("\1n\1h\1y" + msgAreaValidRetval.errorMsg);
							mswait(ERROR_PAUSE_WAIT_MS);
							// Set our loop variables to continue allowing the user to
							// choose a message sub-board
							continueChoosingSubBoard = true;
							continueChoosingMsgGroup = true;
						}
					}
				}
	// If the user chose a different message group & sub-board, then reset the
	// lister index & cursor variables, as well as this.subBoardCode, etc.
	//msg_area.sub[this.subBoardCode].grp_index
	if ((bbs.curgrp != oldGrp) || (bbs.cursub != oldSub))
	{
		this.tradListTopMsgIdx = -1;
		this.lightbarListTopMsgIdx = -1;
		this.lightbarListSelectedMsgIdx = -1;
		this.lightbarListCurPos = null;
		this.setSubBoardCode(msg_area.grp_list[bbs.curgrp].sub_list[bbs.cursub].code);
		// Re-create the msgbase object for the new sub-board.  Don't open it yet,
		// as that is done in the read/list methods.
		if (this.msgbase != null)
		{
			if (this.msgbase.is_open)
				this.msgbase.close();
			this.msgbase = null;
		}
		this.msgbase = new MsgBase(this.subBoardCode);
	}
}

// For the DigDistMsgReader class: Lists all message groups (for the traditional
// user interface).
function DigDistMsgReader_ListMsgGrps_Traditional()
	// Print the header
	this.WriteGrpListHdrLine();
	console.print("\1n");
	// List the message groups
	for (var i = 0; i < msg_area.grp_list.length; ++i)
	{
		console.crlf();
		this.WriteMsgGroupLine(i, false);
	}
}

// For the DigDistMsgReader class: Lists the sub-boards in a message group,
// for the traditional user interface.
//
// Parameters:
//  pGrpIndex: The index of the message group (0-based)
//  pMarkIndex: An index of a message group to highlight.  This
//                   is optional; if left off, this will default to
//                   the current sub-board.
//  pSortType: Optional - A string describing how to sort the list (if desired):
//             "none": Default behavior - Sort by sub-board #
//             "dateAsc": Sort by date, ascending
//             "dateDesc": Sort by date, descending
//             "description": Sort by description
function DigDistMsgReader_ListSubBoardsInMsgGroup_Traditional(pGrpIndex, pMarkIndex, pSortType)
{
	// Default to the current message group & sub-board if pGrpIndex
	// and pMarkIndex aren't specified.
	var grpIndex = bbs.curgrp;
	if ((pGrpIndex != null) && (typeof(pGrpIndex) == "number"))
		grpIndex = pGrpIndex;
	var highlightIndex = bbs.cursub;
	if ((pMarkIndex != null) && (typeof(pMarkIndex) == "number"))
		highlightIndex = pMarkIndex;

	// Make sure grpIndex and highlightIndex are valid (they might not be for
	// brand-new users).
	if ((grpIndex == null) || (typeof(grpIndex) == "undefined"))
		grpIndex = 0;
	if ((highlightIndex == null) || (typeof(highlightIndex) == "undefined"))
		highlightIndex = 0;

	// Ensure that the sub-board printf information is created for
	// this message group.
	this.BuildSubBoardPrintfInfoForGrp(grpIndex);

	// Print the headers
	this.WriteSubBrdListHdr1Line(grpIndex);
	console.crlf();
	printf(this.subBoardListHdrPrintfStr, "Sub #", "Name", "# Posts", "Latest date & time");
	console.print("\1n");
	// List each sub-board in the message group.
	var subBoardArray = null;       // For sorting, if desired
	var newestDate = new Object(); // For storing the date of the newest post in a sub-board
	var msgBase = null;    // For opening the sub-boards with a MsgBase object
	var msgHeader = null;  // For getting the date & time of the newest post in a sub-board
	var subBoardNum = 0;   // 0-based sub-board number (because the array index is the number as a str)
	// If a sort type is specified, then add the sub-board information to
	// subBoardArray so that it can be sorted.
	if ((typeof(pSortType) == "string") && (pSortType != "") && (pSortType != "none"))
	{
		subBoardArray = new Array();
		var subBoardInfo = null;
		for (var arrSubBoardNum in msg_area.grp_list[grpIndex].sub_list)
		{
			// Open the current sub-board with the msgBase object.
			msgBase = new MsgBase(msg_area.grp_list[grpIndex].sub_list[arrSubBoardNum].code);
			if (msgBase.open())
			{
				subBoardInfo = new MsgSubBoardInfo();
				subBoardInfo.subBoardNum = +(arrSubBoardNum);
				subBoardInfo.description = msg_area.grp_list[grpIndex].sub_list[arrSubBoardNum].description;
				subBoardInfo.numPosts = msgBase.total_msgs;
				// Get the date & time when the last message was imported.
				if (msgBase.total_msgs > 0)
				{
					msgHeader = msgBase.get_msg_header(true, msgBase.total_msgs-1, false);
					if (this.msgAreaList_lastImportedMsg_showImportTime)
						subBoardInfo.newestPostDate = msgHeader.when_imported_time
					else
					{
						//subBoardInfo.newestPostDate = msgHeader.when_written_time;
						var msgWrittenLocalTime = msgWrittenTimeToLocalBBSTime(msgHeader);
						if (msgWrittenLocalTime != -1)
							subBoardInfo.newestPostDate = msgWrittenTimeToLocalBBSTime(msgHeader);
						else
							subBoardInfo.newestPostDate = msgHeader.when_written_time;
					}
				}
			}
			msgBase.close();
			subBoardArray.push(subBoardInfo);
		}
		// Free some memory?
		delete msgBase;
		// Possibly sort the sub-board list.
		if (pSortType == "dateAsc")
		{
			subBoardArray.sort(function(pA, pB)
			{
				// Return -1, 0, or 1, depending on whether pA's date comes
				// before, is equal to, or comes after pB's date.
				var returnValue = 0;
				if (pA.newestPostDate < pB.newestPostDate)
					returnValue = -1;
				else if (pA.newestPostDate > pB.newestPostDate)
					returnValue = 1;
				return returnValue;
			});
		}
		else if (pSortType == "dateDesc")
		{
			subBoardArray.sort(function(pA, pB)
			{
				// Return -1, 0, or 1, depending on whether pA's date comes
				// after, is equal to, or comes before pB's date.
				var returnValue = 0;
				if (pA.newestPostDate > pB.newestPostDate)
					returnValue = -1;
				else if (pA.newestPostDate < pB.newestPostDate)
					returnValue = 1;
				return returnValue;
			});
		}
		else if (pSortType == "description")
		{
			// Binary safe string comparison  
			// 
			// version: 909.322
			// discuss at: http://phpjs.org/functions/strcmp    // +   original by: Waldo Malqui Silva
			// +      input by: Steve Hilder
			// +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
			// +    revised by: gorthaur
			// *     example 1: strcmp( 'waldo', 'owald' );    // *     returns 1: 1
			// *     example 2: strcmp( 'owald', 'waldo' );
			// *     returns 2: -1
			subBoardArray.sort(function(pA, pB)
			{
				return ((pA.description == pB.description) ? 0 : ((pA.description > pB.description) ? 1 : -1));
			});
		}
		// Display the sub-board list.
		for (var i = 0; i < subBoardArray.length; ++i)
		{
			console.crlf();
			console.print((subBoardArray[i].subBoardNum == highlightIndex) ? "\1n" +
			              this.colors.areaChooserMsgAreaMarkColor + "*" : " ");
			printf(this.subBoardListPrintfInfo[grpIndex].printfStr, +(subBoardArray[i].subBoardNum+1),
			       subBoardArray[i].description.substr(0, this.subBoardNameLen),
			       subBoardArray[i].numPosts, strftime("%Y-%m-%d", subBoardArray[i].newestPostDate),
			       strftime("%H:%M:%S", subBoardArray[i].newestPostDate));
		}
	}
	// If no sort type is specified, then output the sub-board information in
	// order of sub-board number.
	else
	{
		for (var arrSubBoardNum in msg_area.grp_list[grpIndex].sub_list)
		{
			// Open the current sub-board with the msgBase object.
			msgBase = new MsgBase(msg_area.grp_list[grpIndex].sub_list[arrSubBoardNum].code);
			if (msgBase.open())
			{
				// Get the date & time when the last message was imported.
				if (msgBase.total_msgs > 0)
				{
					msgHeader = msgBase.get_msg_header(true, msgBase.total_msgs-1, false);
					// Construct the date & time strings of the latest post
					if (this.msgAreaList_lastImportedMsg_showImportTime)
					{
						newestDate.date = strftime("%Y-%m-%d", msgHeader.when_imported_time);
						newestDate.time = strftime("%H:%M:%S", msgHeader.when_imported_time);
					}
					else
					{
						//newestDate.date = strftime("%Y-%m-%d", msgHeader.when_written_time);
						//newestDate.time = strftime("%H:%M:%S", msgHeader.when_written_time);
						var msgWrittenLocalTime = msgWrittenTimeToLocalBBSTime(msgHeader);
						if (msgWrittenLocalTime != -1)
						{
							newestDate.date = strftime("%Y-%m-%d", msgWrittenLocalTime);
							newestDate.time = strftime("%H:%M:%S", msgWrittenLocalTime);
						}