Skip to content
Snippets Groups Projects
DDMsgReader.js 750 KiB
Newer Older
					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);
						}
						else
						{
							newestDate.date = strftime("%Y-%m-%d", msgHeader.when_written_time);
							newestDate.time = strftime("%H:%M:%S", msgHeader.when_written_time);
						}
				// Print the sub-board information
				subBoardNum = +(arrSubBoardNum);
				console.crlf();
				console.print((subBoardNum == highlightIndex) ? "\1n" +
				              this.colors.areaChooserMsgAreaMarkColor + "*" : " ");
				printf(this.subBoardListPrintfInfo[grpIndex].printfStr, +(subBoardNum+1),
				       msg_area.grp_list[grpIndex].sub_list[arrSubBoardNum].description.substr(0, this.subBoardListPrintfInfo[grpIndex].nameLen),
				       msgBase.total_msgs, newestDate.date, newestDate.time);
}

//////////////////////////////////////////////
// Message group list stuff (lightbar mode) //
//////////////////////////////////////////////

// Displays a screenful of message groups, for the lightbar interface.
//
// Parameters:
//  pStartIndex: The message group index to start at (0-based)
//  pStartScreenRow: The row on the screen to start at (1-based)
//  pEndScreenRow: The row on the screen to end at (1-based)
//  pClearScreenFirst: Boolean - Whether or not to clear the screen first
//  pBlankToEndRow: Boolean - Whether or not to write blank lines to the end
//                  screen row if there aren't enough message groups to fill
//                  the screen.
function DigDistMsgReader_listScreenfulOfMsgGrps(pStartIndex, pStartScreenRow,
                                                  pEndScreenRow, pClearScreenFirst,
                                                  pBlankToEndRow)
{
	// Check the parameters; If they're bad, then just return.
	if ((typeof(pStartIndex) != "number") ||
	    (typeof(pStartScreenRow) != "number") ||
	    (typeof(pEndScreenRow) != "number"))
	{
		return;
	}
	if ((pStartIndex < 0) || (pStartIndex >= msg_area.grp_list.length))
		return;
	if ((pStartScreenRow < 1) || (pStartScreenRow > console.screen_rows))
		return;
	if ((pEndScreenRow < 1) || (pEndScreenRow > console.screen_rows))
		return;
	// If pStartScreenRow is greather than pEndScreenRow, then swap them.
	if (pStartScreenRow > pEndScreenRow)
	{
		var temp = pStartScreenRow;
		pStartScreenRow = pEndScreenRow;
		pEndScreenRow = temp;
	}
	// Calculate the ending index to use for the message groups array.
	var endIndex = pStartIndex + (pEndScreenRow-pStartScreenRow);
	if (endIndex >= msg_area.grp_list.length)
		endIndex = msg_area.grp_list.length - 1;
	var onePastEndIndex = endIndex + 1;
	// Clear the screen, go to the specified screen row, and display the message
	// group information.
	if (pClearScreenFirst)
		console.clear("\1n");
	console.gotoxy(1, pStartScreenRow);
	var grpIndex = pStartIndex;
	for (; grpIndex < onePastEndIndex; ++grpIndex)
	{
		this.WriteMsgGroupLine(grpIndex, false);
		if (grpIndex < endIndex)
			console.crlf();
	}
	// If pBlankToEndRow is true and we're not at the end row yet, then
	// write blank lines to the end row.
	if (pBlankToEndRow)
	{
		var screenRow = pStartScreenRow + (endIndex - pStartIndex) + 1;
		if (screenRow <= pEndScreenRow)
		{
			for (; screenRow <= pEndScreenRow; ++screenRow)
			{
				console.gotoxy(1, screenRow);
				console.clearline("\1n");
			}
		}
	}
}

// For the DigDistMsgReader class - Writes a message group information line.
//
// Parameters:
//  pGrpIndex: The index of the message group to write (assumed to be valid)
//  pHighlight: Boolean - Whether or not to write the line highlighted.
function DigDistMsgReader_writeMsgGroupLine(pGrpIndex, pHighlight)
{
	// TODO: If pHighlight is true, that causes the screen to be cleared
	// and the line is written on the first row of the console.
	console.print("\1n");
	// Write the highlight background color if pHighlight is true.
	if (pHighlight)
	console.print(this.colors.areaChooserMsgAreaBkgHighlightColor);
	// Write the message group information line
	console.print(((typeof(bbs.curgrp) == "number") && (pGrpIndex == msg_area.sub[this.subBoardCode].grp_index)) ? this.colors.areaChooserMsgAreaMarkColor + "*" : " ");
	printf((pHighlight ? this.msgGrpListHilightPrintfStr : this.msgGrpListPrintfStr),
	       +(pGrpIndex+1),
	       msg_area.grp_list[pGrpIndex].description.substr(0, this.msgGrpDescLen),
	       msg_area.grp_list[pGrpIndex].sub_list.length);
	console.cleartoeol("\1n");
}

//////////////////////////////////////////////////
// Message sub-board list stuff (lightbar mode) //
//////////////////////////////////////////////////

// Updates the page number text in the group list header line on the screen.
//
// Parameters:
//  pPageNum: The page number
//  pNumPages: The total number of pages
//  pGroup: Boolean - Whether or not this is for the group header.  If so,
//          then this will go to the right location for the group page text
//          and use this.colors.areaChooserMsgAreaHeaderColor for the text.
//          Otherwise, this will go to the right place for the sub-board page
//          text and use the sub-board header color.
//  pRestoreCurPos: Optional - Boolean - If true, then move the cursor back
//                  to the position where it was before this function was called
function DigDistMsgReader_updateMsgAreaPageNumInHeader(pPageNum, pNumPages, pGroup, pRestoreCurPos)
{
	var originalCurPos = null;
	if (pRestoreCurPos)
		originalCurPos = console.getxy();
nightfox's avatar
nightfox committed
		console.gotoxy(29, 1+this.areaChangeHdrLines.length);
		console.print("\1n" + this.colors.areaChooserMsgAreaHeaderColor + pPageNum + " of " +
		              pNumPages + ")   ");
	}
	else
	{
nightfox's avatar
nightfox committed
		console.gotoxy(51, 1+this.areaChangeHdrLines.length);
		console.print("\1n" + this.colors.areaChooserSubBoardHeaderColor + pPageNum + " of " +
		              pNumPages + ")   ");
	}
	if (pRestoreCurPos)
		console.gotoxy(originalCurPos);
}

// Displays a screenful of message sub-boards, for the lightbar interface.
//
// Parameters:
//  pGrpIndex: The index of the message group (0-based)
//  pStartSubIndex: The message sub-board index to start at (0-based)
//  pStartScreenRow: The row on the screen to start at (1-based)
//  pEndScreenRow: The row on the screen to end at (1-based)
//  pClearScreenFirst: Boolean - Whether or not to clear the screen first
//  pBlankToEndRow: Boolean - Whether or not to write blank lines to the end
//                  screen row if there aren't enough message groups to fill
//                  the screen.
function DigDistMsgReader_ListScreenfulOfSubBrds(pGrpIndex, pStartSubIndex,
                                                  pStartScreenRow, pEndScreenRow,
                                                  pClearScreenFirst, pBlankToEndRow)
{
	// Check the parameters; If they're bad, then just return.
	if ((typeof(pGrpIndex) != "number") ||
	    (typeof(pStartSubIndex) != "number") ||
	    (typeof(pStartScreenRow) != "number") ||
	    (typeof(pEndScreenRow) != "number"))
	{
		return;
	}
	if ((pGrpIndex < 0) || (pGrpIndex >= msg_area.grp_list.length))
		return;
	if ((pStartSubIndex < 0) ||
	    (pStartSubIndex >= msg_area.grp_list[pGrpIndex].sub_list.length))
	{
		return;
	}
	if ((pStartScreenRow < 1) || (pStartScreenRow > console.screen_rows))
		return;
	if ((pEndScreenRow < 1) || (pEndScreenRow > console.screen_rows))
		return;
	// If pStartScreenRow is greather than pEndScreenRow, then swap them.
	if (pStartScreenRow > pEndScreenRow)
	{
		var temp = pStartScreenRow;
		pStartScreenRow = pEndScreenRow;
		pEndScreenRow = temp;
	}
	// Calculate the ending index to use for the sub-board array.
	var endIndex = pStartSubIndex + (pEndScreenRow-pStartScreenRow);
	if (endIndex >= msg_area.grp_list[pGrpIndex].sub_list.length)
		endIndex = msg_area.grp_list[pGrpIndex].sub_list.length - 1;
	var onePastEndIndex = endIndex + 1;
	// Clear the screen and go to the specified screen row.
	if (pClearScreenFirst)
		console.clear("\1n");
	console.gotoxy(1, pStartScreenRow);
	var subIndex = pStartSubIndex;
	for (; subIndex < onePastEndIndex; ++subIndex)
	{
		this.WriteMsgSubBoardLine(pGrpIndex, subIndex, false);
		if (subIndex < endIndex)
			console.crlf();
	}
	// If pBlankToEndRow is true and we're not at the end row yet, then
	// write blank lines to the end row.
	if (pBlankToEndRow)
	{
		var screenRow = pStartScreenRow + (endIndex - pStartSubIndex) + 1;
		if (screenRow <= pEndScreenRow)
		{
			for (; screenRow <= pEndScreenRow; ++screenRow)
			{
				console.gotoxy(1, screenRow);
				console.clearline("\1n");
			}
		}
	}
}

// For the DigDistMsgReader class: Writes a message sub-board information line for
// the message area chooser functionality.
//
// Parameters:
//  pGrpIndex: The index of the message group (assumed to be valid)
//  pSubIndex: The index of the sub-board within the message group to write (assumed to be valid)
//  pHighlight: Boolean - Whether or not to write the line highlighted.
function DigDistMsgReader_WriteMsgSubBrdLine(pGrpIndex, pSubIndex, pHighlight)
	console.print("\1n");
	// Write the highlight background color if pHighlight is true.
	if (pHighlight)
		console.print(this.colors.areaChooserMsgAreaBkgHighlightColor);

	// Determine if pGrpIndex and pSubIndex specify the user's
	// currently-selected group and sub-board.
	var currentSub = false;
	if ((typeof(bbs.curgrp) == "number") && (typeof(bbs.cursub) == "number"))
		currentSub = ((pGrpIndex == msg_area.sub[this.subBoardCode].grp_index) && (pSubIndex == msg_area.sub[this.subBoardCode].index));

	// Open the current sub-board with the msgBase object (so that we can get
	// the date & time of the last imporeted message).
	var msgBase = new MsgBase(msg_area.grp_list[pGrpIndex].sub_list[pSubIndex].code);
	if (msgBase.open())
	{
		var newestDate = new Object(); // For storing the date of the newest post
		// Get the date & time when the last message was imported.
		if (msgBase.total_msgs > 0)
		{
			// Get the header of the last message in the sub-board
			msgHeader = null;
			var msgOffset = msgBase.total_msgs - 1;
			while ((msgHeader === null) && (msgOffset >= 0))
			{
				msgHeader = msgBase.get_msg_header(true, msgOffset, false);
				--msgOffset;
			}
			// 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);
				}
				else
				{
					newestDate.date = strftime("%Y-%m-%d", msgHeader.when_written_time);
					newestDate.time = strftime("%H:%M:%S", msgHeader.when_written_time);
				}
		// Print the sub-board information line.
		console.print(currentSub ? this.colors.areaChooserMsgAreaMarkColor + "*" : " ");
		printf((pHighlight ? this.subBoardListPrintfInfo[pGrpIndex].highlightPrintfStr : this.subBoardListPrintfInfo[pGrpIndex].printfStr),
		       +(pSubIndex+1),
		msg_area.grp_list[pGrpIndex].sub_list[pSubIndex].description.substr(0, this.subBoardListPrintfInfo[pGrpIndex].nameLen),
		                                                                    msgBase.total_msgs, newestDate.date, newestDate.time);
		msgBase.close();

		delete msgBase;
	}
}

///////////////////////////////////////////////
// Other functions for the msg. area chooser //
///////////////////////////////////////////////

// For the DigDistMsgReader class: Shows the help screen
//
// Parameters:
//  pLightbar: Boolean - Whether or not to show lightbar help.  If
//             false, then this function will show regular help.
//  pClearScreen: Boolean - Whether or not to clear the screen first
function DigDistMsgReader_showChooseMsgAreaHelpScreen(pLightbar, pClearScreen)
{
   if (pClearScreen && console.term_supports(USER_ANSI))
      console.clear("\1n");
   else
      console.print("\1n");
   DisplayProgramInfo();
   console.crlf();
   console.print("\1n\1c\1hMessage area (sub-board) chooser");
   console.crlf();
   console.print("\1kÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\1n");
   console.crlf();
   console.print("\1cFirst, a listing of message groups is displayed.  One can be chosen by typing");
   console.crlf();
   console.print("its number.  Then, a listing of sub-boards within that message group will be");
   console.crlf();
   console.print("shown, and one can be chosen by typing its number.");
   console.crlf();

   if (pLightbar)
   {
      console.crlf();
      console.print("\1n\1cThe lightbar interface also allows up & down navigation through the lists:");
      console.crlf();
      console.print("\1k\1hÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ");
      console.crlf();
      console.print("\1n\1c\1hUp arrow\1n\1c: Move the cursor up one line");
      console.crlf();
      console.print("\1hDown arrow\1n\1c: Move the cursor down one line");
      console.crlf();
      console.print("\1hENTER\1n\1c: Select the current group/sub-board");
      console.crlf();
      console.print("\1hHOME\1n\1c: Go to the first item on the screen");
      console.crlf();
      console.print("\1hEND\1n\1c: Go to the last item on the screen");
      console.crlf();
      console.print("\1hF\1n\1c: Go to the first page");
      console.crlf();
      console.print("\1hL\1n\1c: Go to the last page");
      console.crlf();
   }

   console.crlf();
   console.print("Additional keyboard commands:");
   console.crlf();
   console.print("\1k\1hÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ");
   console.crlf();
   console.print("\1n\1c\1h?\1n\1c: Show this help screen");
   console.crlf();
   console.print("\1hQ\1n\1c: Quit");
   console.crlf();
}

// Builds sub-board printf format information for a message group.
// The widths of the description & # messages columns are calculated
// based on the greatest number of messages in a sub-board for the
// message group.
//
// Parameters:
//  pGrpIndex: The index of the message group
function DigDistMsgReader_BuildSubBoardPrintfInfoForGrp(pGrpIndex)
{
   // If the array of sub-board printf strings doesn't contain the printf
   // strings for this message group, then figure out the largest number
   // of messages in the message group and add the printf strings.
   if (typeof(this.subBoardListPrintfInfo[pGrpIndex]) == "undefined")
   {
      var greatestNumMsgs = getGreatestNumMsgs(pGrpIndex);

      this.subBoardListPrintfInfo[pGrpIndex] = new Object();
      this.subBoardListPrintfInfo[pGrpIndex].numMsgsLen = greatestNumMsgs.toString().length;
      // Sub-board name length: With a # items length of 4, this should be
      // 47 for an 80-column display.
      this.subBoardListPrintfInfo[pGrpIndex].nameLen = console.screen_columns -
                                   this.areaNumLen -
                                   this.subBoardListPrintfInfo[pGrpIndex].numMsgsLen -
                                   this.dateLen - this.timeLen - 7;
      // Create the printf strings
      this.subBoardListPrintfInfo[pGrpIndex].printfStr =
               " " + this.colors.areaChooserMsgAreaNumColor
               + "%" + this.areaNumLen + "d "
               + this.colors.areaChooserMsgAreaDescColor + "%-"
               + this.subBoardListPrintfInfo[pGrpIndex].nameLen + "s "
               + this.colors.areaChooserMsgAreaNumItemsColor + "%"
               + this.subBoardListPrintfInfo[pGrpIndex].numMsgsLen + "d "
               + this.colors.areaChooserMsgAreaLatestDateColor + "%" + this.dateLen + "s "
               + this.colors.areaChooserMsgAreaLatestTimeColor + "%" + this.timeLen + "s";
      this.subBoardListPrintfInfo[pGrpIndex].highlightPrintfStr =
                              "\1n" + this.colors.areaChooserMsgAreaBkgHighlightColor + " "
                              + "\1n" + this.colors.areaChooserMsgAreaBkgHighlightColor
                              + this.colors.areaChooserMsgAreaNumHighlightColor
                              + "%" + this.areaNumLen + "d \1n"
                              + this.colors.areaChooserMsgAreaBkgHighlightColor
                              + this.colors.areaChooserMsgAreaDescHighlightColor + "%-"
                              + this.subBoardListPrintfInfo[pGrpIndex].nameLen + "s \1n"
                              + this.colors.areaChooserMsgAreaBkgHighlightColor
                              + this.colors.areaChooserMsgAreaNumItemsHighlightColor + "%"
                              + this.subBoardListPrintfInfo[pGrpIndex].numMsgsLen + "d \1n"
                              + this.colors.areaChooserMsgAreaBkgHighlightColor
                              + this.colors.areaChooserMsgAreaDateHighlightColor + "%" + this.dateLen + "s \1n"
                              + this.colors.areaChooserMsgAreaBkgHighlightColor
                              + this.colors.areaChooserMsgAreaTimeHighlightColor + "%" + this.timeLen + "s\1n";
   }
}

// Returns an array of strings containing extended message header information,
// such as the kludge lines (for FidoNet-style networks), etc.
// For each kludge line, there will be a label string for the info line, the
// info line itself (wrapped to fit the message area width), then a blank
// line (except for the last kludge line).  The info lines that this method
// retrieves will only be retrieved if they exist in the given message header.
//
// Parameters:
//  pMsgHdr: A message header
//  pKludgeOnly: Boolean - Whether or not to only get the kludge lines.  If false,
//               then all header fields will be retrieved.
//
// Return value: An array of strings containing the extended message header information
function DigDistMsgReader_GetExtdMsgHdrInfo(pMsgHdr, pKludgeOnly)
{
	// If pMsgHdr is not valid, then just return an empty array.
	if (typeof(pMsgHdr) != "object")
		return new Array();

	// Get the message header with fields expanded so we can get the most info possible.
	var msgHdr = this.GetMsgHdrByAbsoluteNum(pMsgHdr.number, true, true);
	// The message header retrieved that way might not have vote information,
	// so copy any additional header information from this.hdrsForCurrentSubBoard
	// if there's a header there for this message.
	if (this.hdrsForCurrentSubBoardByMsgNum.hasOwnProperty(pMsgHdr.number))
	{
		var tmpHdrIdx = this.hdrsForCurrentSubBoardByMsgNum[pMsgHdr.number];
		if (this.hdrsForCurrentSubBoard.hasOwnProperty(tmpHdrIdx))
		{
			for (var hdrProp in this.hdrsForCurrentSubBoard[tmpHdrIdx])
			{
				if (!msgHdr.hasOwnProperty(hdrProp))
					msgHdr[hdrProp] = this.hdrsForCurrentSubBoard[tmpHdrIdx][hdrProp];
			}
		}
	}
	var msgHdrInfoLines = new Array();
	var kludgeOnly = (typeof(pKludgeOnly) == "boolean" ? pKludgeOnly : false);
	if (kludgeOnly)
	{
		hdrInfoLineFields.push({ field: "ftn_msgid", label: "MSG ID:" });
		hdrInfoLineFields.push({ field: "X-FTN-MSGID", label: "MSG ID:" });
		hdrInfoLineFields.push({ field: "ftn_reply", label: "Reply ID:" });
		hdrInfoLineFields.push({ field: "X-FTN-REPLY", label: "Reply ID:" });
		hdrInfoLineFields.push({ field: "ftn_area", label: "Area tag:" });
		hdrInfoLineFields.push({ field: "X-FTN-AREA", label: "Area tag:" });
		hdrInfoLineFields.push({ field: "ftn_flags", label: "Flags:" });
		hdrInfoLineFields.push({ field: "ftn_pid", label: "Program ID:" });
		hdrInfoLineFields.push({ field: "ftn_tid", label: "Tosser ID:" });
		hdrInfoLineFields.push({ field: "X-FTN-TID", label: "Tosser ID:" });
		hdrInfoLineFields.push({ field: "X-FTN-Kludge", label: "Kludge:" });
		hdrInfoLineFields.push({ field: "X-FTN-SEEN-BY", label: "Seen-By:" });
		hdrInfoLineFields.push({ field: "X-FTN-PATH", label: "Path:" });