Newer
Older
msgbase.close();
return retObj;
}
// New MsgBase method: vote_msg(). it takes a message header object
// (like save_msg), except you only need a few properties, in order of
// importarnce:
// attr: you need to have this set to MSG_UPVOTE, MSG_DOWNVOTE, or MSG_VOTE
// thread_back or reply_id: either of these must be set to indicate msg to vote on
// from: name of voter
// from_net_type and from_net_addr: if applicable
// Do some initial setup of the header for the vote message to be
// saved to the messagebase
var voteMsgHdr = new Object();
voteMsgHdr.thread_back = pMsgHdr.number;
voteMsgHdr.reply_id = pMsgHdr.id;
voteMsgHdr.from = (msgbase.cfg.settings & SUB_NAME) == SUB_NAME ? user.name : user.alias;
if (pMsgHdr.from.hasOwnProperty("from_net_type"))
{
voteMsgHdr.from_net_type = pMsgHdr.from_net_type;
if (pMsgHdr.from_net_type != NET_NONE)
voteMsgHdr.from_net_addr = user.email;
}
// Input vote options from the user differently depending on whether
// the message is a poll or not
if ((pMsgHdr.attr & MSG_POLL) == MSG_POLL)
{
if (pMsgHdr.hasOwnProperty("field_list"))
{
console.clear("\1n");

nightfox
committed
var selectHdr = bbs.text(typeof(BallotHdr) != "undefined" ? BallotHdr : 791);
printf("\1n" + selectHdr + "\1n", pMsgHdr.subject);
var optionFormatStr = "\1n\1c\1h%2d\1n\1c: \1h%s\1n";
var optionNum = 1;
for (var fieldI = 0; fieldI < pMsgHdr.field_list.length; ++fieldI)
{
if (pMsgHdr.field_list[fieldI].type == SMB_POLL_ANSWER)
{
printf(optionFormatStr, optionNum++, pMsgHdr.field_list[fieldI].data);
console.crlf();
}
}
console.crlf();
// Get & process the selection from the user
var userInputNum = 0;
if (pMsgHdr.votes > 1)
{
// Support multiple answers from the user
console.print("\1n\1gYour vote numbers, separated by commas, up to \1h" + pMsgHdr.votes + "\1n\1g (Blank/Q=Quit):");
console.crlf();
console.print("\1c\1h");
var userInput = consoleGetStrWithValidKeys("0123456789,Q", null, false);
14055
14056
14057
14058
14059
14060
14061
14062
14063
14064
14065
14066
14067
14068
14069
14070
14071
14072
14073
14074
14075
14076
14077
14078
14079
14080
14081
14082
14083
14084
14085
14086
14087
14088
14089
14090
14091
14092
14093
14094
if ((userInput.length > 0) && (userInput.toUpperCase() != "Q"))
{
var userAnswers = userInput.split(",");
if (userAnswers.length > 0)
{
// Generate confirmation text and an array of numbers
// representing the user's choices, up to the number
// of responses allowed
var confirmText = "Vote ";
var voteNumbers = [];
for (var i = 0; (i < userAnswers.length) && (i < pMsgHdr.votes); ++i)
{
// Trim any whitespace from the user's response
userAnswers[i] = trimSpaces(userAnswers[i], true, true, true);
if (/^[0-9]+$/.test(userAnswers[i]))
{
voteNumbers.push(+userAnswers[i]);
confirmText += userAnswers[i] + ",";
}
}
// If the confirmation text has a trailing comma, remove it
if (/,$/.test(confirmText))
confirmText = confirmText.substr(0, confirmText.length-1);
// Confirm from the user and submit their vote if they say yes
if (voteNumbers.length > 0)
{
if (console.yesno(confirmText))
{
userInputNum = 0;
for (var i = 0; i < voteNumbers.length; ++i)
userInputNum |= (1 << (voteNumbers[i]-1));
}
else
retObj.userQuit = true;
}
}
}
else
retObj.userQuit = true;
}
else
{
// Get the selection prompt text from text.dat and replace the %u or %d with
// the number 1 (default option)
var selectPromptText = bbs.text(SelectItemWhich);
selectPromptText = selectPromptText.replace(/%[uU]/, 1).replace(/%[dD]/, 1);
console.mnemonics(selectPromptText);
var maxNum = optionNum - 1;
userInputNum = console.getnum(maxNum);
if (userInputNum == -1) // The user chose Q to quit
retObj.userQuit = true;
console.print("\1n");
}
if (!retObj.userQuit)
{
voteMsgHdr.attr = MSG_VOTE;
voteMsgHdr.votes = userInputNum;
}
}
}
else
// The message is not a poll - Prompt for up/downvote
if ((typeof(MSG_UPVOTE) != "undefined") && (typeof(MSG_DOWNVOTE) != "undefined"))
{
var voteAttr = 0;
// Get text line 783 to prompt for voting
var textDatText = bbs.text(typeof(VoteMsgUpDownOrQuit) != "undefined" ? VoteMsgUpDownOrQuit : 783);
if (removeNLsFromVoteText)
textDatText = textDatText.replace("\r\n", "").replace("\n", "").replace("\N", "").replace("\r", "").replace("\R", "").replace("\R\n", "").replace("\r\N", "").replace("\R\N", "");
console.print("\1n");
console.mnemonics(textDatText);
console.print("\1n");
// Using getAllowedKeyWithMode() instead of console.getkeys() so we
// can control the input mode better, so it doesn't output a CRLF
switch (getAllowedKeyWithMode("UDQ" + KEY_UP + KEY_DOWN, K_NOCRLF|K_NOSPIN))
{
case "U":
case KEY_UP:
voteAttr = MSG_UPVOTE;
break;
case "D":
case KEY_DOWN:
voteAttr = MSG_DOWNVOTE;
break;
case "Q":
default:
retObj.userQuit = true;
break;
}
// If the user voted, then save the user's vote in the attr property
// in the header
if (voteAttr != 0)
voteMsgHdr.attr = voteAttr;
}
else
retObj.errorMsg = "MSG_UPVOTE & MSG_DOWNVOTE are not defined";
}
// If the user hasn't quit and there is no error message, then save the vote
// message header
if (!retObj.userQuit && (retObj.errorMsg.length == 0))
{
console.print("\1n Submitting.."); // TODO: Does this look good?
retObj.savedVote = msgbase.vote_msg(voteMsgHdr);
// If the save was successful, then update
// this.hdrsForCurrentSubBoard with the updated
// message header (for the message that was read)
if (retObj.savedVote)
{
if (this.hdrsForCurrentSubBoardByMsgNum.hasOwnProperty(pMsgHdr.number))
{
var originalMsgIdx = this.hdrsForCurrentSubBoardByMsgNum[pMsgHdr.number];
if (typeof(msgbase.get_all_msg_headers) === "function")
var tmpHdrs = msgbase.get_all_msg_headers();
if (tmpHdrs.hasOwnProperty(pMsgHdr.number))
this.hdrsForCurrentSubBoard[originalMsgIdx] = tmpHdrs[pMsgHdr.number];
retObj.updatedHdr = pMsgHdr;
if (this.hdrsForCurrentSubBoard[originalMsgIdx].hasOwnProperty("total_votes"))
retObj.updatedHdr.total_votes = this.hdrsForCurrentSubBoard[originalMsgIdx].total_votes;
if (this.hdrsForCurrentSubBoard[originalMsgIdx].hasOwnProperty("upvotes"))
retObj.updatedHdr.upvotes = this.hdrsForCurrentSubBoard[originalMsgIdx].upvotes;
if (this.hdrsForCurrentSubBoard[originalMsgIdx].hasOwnProperty("tally"))
retObj.updatedHdr.tally = this.hdrsForCurrentSubBoard[originalMsgIdx].tally;
}
}
}
}
else
{
// Failed to save the vote
retObj.errorMsg = "Failed to save your vote";
}
msgbase.close();
return retObj;
}
// For the DigDistMsgReader class: Checks to see whether a user has voted on a message.
// The message must belong to the currently-open sub-board.
//
// Parameters:
// pMsgNum: The message number
// pUser: Optional - A user account to check. If omitted, the current logged-in
// user will be used.
function DigDistMsgReader_HasUserVotedOnMsg(pMsgNum, pUser)
{

nightfox
committed
// Don't do this for personal email
if (this.subBoardCode == "mail")
return false;
// Thanks to echicken for explaining how to check this. To check a user's
// vote, use MsgBase.how_user_voted().
/*
The return value will be:
0 - user hasn't voted
1 - upvoted
2 - downvoted
Or, if the message was a poll, it's a bitfield:
if (votes&(1<<2)) {
// User selected answer 2
}
*/
var userHasVotedOnMsg = false;
var msgbase = new MsgBase(this.subBoardCode);
if (msgbase.open())
{
if (typeof(msgbase.how_user_voted) === "function")
{
var votes = 0;
if (typeof(pUser) == "object")
votes = msgbase.how_user_voted(pMsgNum, (msgbase.cfg.settings & SUB_NAME) == SUB_NAME ? pUser.name : pUser.alias);
else
votes = msgbase.how_user_voted(pMsgNum, (msgbase.cfg.settings & SUB_NAME) == SUB_NAME ? user.name : user.alias);
userHasVotedOnMsg = (votes > 0);
}
msgbase.close();
}
return userHasVotedOnMsg;
}

nightfox
committed
// Gets information about the upvotes and downvotes for a message.
// If the user is a sysop, this will also get who voted on the message.
//
// Parameters:
// pMsgHdr: A header of a message that has upvotes & downvotes
//
// Return value: An array of strings containing information about the upvotes,
// downvotes, tally, and (if the user is a sysop) who submitted
// votes on the message.
function DigDistMsgReader_GetUpvoteAndDownvoteInfo(pMsgHdr)
{
// If the message header doesn't have the "total_votes" or "upvotes" properties,
// then there's no vote information, so just return an empty array.
if (!pMsgHdr.hasOwnProperty("total_votes") || !pMsgHdr.hasOwnProperty("upvotes"))
return [];
var voteInfo = getMsgUpDownvotesAndScore(pMsgHdr);

nightfox
committed
var voteInfo = [];
voteInfo.push("Upvotes: " + voteInfo.upvotes);
voteInfo.push("Downvotes: " + voteInfo.downvotes);
voteInfo.push("Score: " + voteInfo.voteScore);

nightfox
committed
if (pMsgHdr.hasOwnProperty("tally"))
voteInfo.push("Tally: " + pMsgHdr.tally);
if (gIsSysop)
{
// Check all the messages in the messagebase after the current one
// to find response messages
var msgbase = new MsgBase(this.subBoardCode);
if (msgbase.open())

nightfox
committed
{
if (typeof(msgbase.get_all_msg_headers) === "function")

nightfox
committed
{
// Pass true to get_all_msg_headers() to tell it to return vote messages
// (the parameter was introduced in Synchronet 3.17+)
var tmpHdrs = msgbase.get_all_msg_headers(true);
for (var tmpProp in tmpHdrs)

nightfox
committed
{
if (tmpHdrs[tmpProp] == null)
continue;
// If this header's thread_back or reply_id matches the poll message
// number, then append the 'user voted' string to the message body.
if ((tmpHdrs[tmpProp].thread_back == pMsgHdr.number) || (tmpHdrs[tmpProp].reply_id == pMsgHdr.id))

nightfox
committed
{
var tmpMessageBody = msgbase.get_msg_body(false, tmpHdrs[tmpProp].number);
if ((tmpHdrs[tmpProp].field_list.length == 0) && (tmpMessageBody.length == 0))
{
var msgWrittenLocalTime = msgWrittenTimeToLocalBBSTime(tmpHdrs[tmpProp]);
var voteDate = strftime("%a %b %d %Y %H:%M:%S", msgWrittenLocalTime);
voteInfo.push("\1n\1c\1h" + tmpHdrs[tmpProp].from + "\1n\1c voted on this message on " + voteDate + "\1n");
}

nightfox
committed
}
}
}
msgbase.close();

nightfox
committed
}
}
return voteInfo;
}
// For the DigDistMsgReader class: Gets the body (text) of a message. If it's
// a poll, this method will format the message body with poll results. Otherwise,
// this method will simply get the message body.
//
// Parameters:
// pMsgHeader: The message header
//
// Return value: The poll results, colorized. If the message is not a
// poll message, then an empty string will be returned.
function DigDistMsgReader_GetMsgBody(pMsgHdr)
{
var msgbase = new MsgBase(this.subBoardCode);
if (!msgbase.open())
return "";
14315
14316
14317
14318
14319
14320
14321
14322
14323
14324
14325
14326
14327
14328
14329
14330
14331
var msgBody = "";
if ((typeof(MSG_TYPE_POLL) != "undefined") && (pMsgHdr.type & MSG_TYPE_POLL) == MSG_TYPE_POLL)
{
// A poll is intended to be parsed (and displayed) using on the header data. The
// (optional) comments are stored in the hdr.field_list[] with type values of
// SMB_COMMENT (now defined in sbbsdefs.js) and the available answers are in the
// field_list[] with type values of SMB_POLL_ANSWER.
// The 'comments' and 'answers' are also a part of the message header, so you can
// grab them separately, then format and display them however you want. You can
// find them in the header.field_list array; each element in that array should be
// an object with a 'type' and a 'data' property. Relevant types here are
// SMB_COMMENT and SMB_POLL_ANSWER. (This is what I'm doing on the web, and I
// just ignore the message body for poll messages.)
if (pMsgHdr.hasOwnProperty("field_list"))
{
14332
14333
14334
14335
14336
14337
14338
14339
14340
14341
14342
14343
14344
14345
14346
14347
14348
14349
14350
// Figure out the longest length of the poll choices, with
// a maximum of 22 characters less than the terminal width.
// Use a minimum of 27 characters.
// That length will be used for the formatting strings for
// the poll results.
var voteOptDescLen = 0;
for (var fieldI = 0; fieldI < pMsgHdr.field_list.length; ++fieldI)
{
if (pMsgHdr.field_list[fieldI].type == SMB_POLL_ANSWER)
{
if (pMsgHdr.field_list[fieldI].data.length > voteOptDescLen)
voteOptDescLen = pMsgHdr.field_list[fieldI].data.length;
}
}
if (voteOptDescLen > console.screen_columns - 22)
voteOptDescLen = console.screen_columns - 22;
else if (voteOptDescLen < 27)
voteOptDescLen = 27;
// Format strings for outputting the voting option lines
var unvotedOptionFormatStr = "\1n\1c\1h%2d\1n\1c: \1w\1h%-" + voteOptDescLen + "s [%-4d %6.2f%]\1n";
var votedOptionFormatStr = "\1n\1c\1h%2d\1n\1c: \1" + "5\1w\1h%-" + voteOptDescLen + "s [%-4d %6.2f%]\1n";
// Add up the total number of votes so that we can
// calculate vote percentages.
var totalNumVotes = 0;
if (pMsgHdr.hasOwnProperty("tally"))
{
for (var tallyI = 0; tallyI < pMsgHdr.tally.length; ++tallyI)
totalNumVotes += pMsgHdr.tally[tallyI];
}
// Go through field_list and append the voting options and stats to
// msgBody
var pollComment = "";
var optionNum = 1;
var numVotes = 0;
var votePercentage = 0;
var tallyIdx = 0;
for (var fieldI = 0; fieldI < pMsgHdr.field_list.length; ++fieldI)
{
if (pMsgHdr.field_list[fieldI].type == SMB_COMMENT)
pollComment += pMsgHdr.field_list[fieldI].data + "\r\n";
else if (pMsgHdr.field_list[fieldI].type == SMB_POLL_ANSWER)
{
// Figure out the number of votes on this option and the
// vote percentage
if (pMsgHdr.hasOwnProperty("tally"))
{
if (tallyIdx < pMsgHdr.tally.length)
{
numVotes = pMsgHdr.tally[tallyIdx];
votePercentage = (numVotes / totalNumVotes) * 100;
}
}
// Append to the message text
msgBody += format(numVotes == 0 ? unvotedOptionFormatStr : votedOptionFormatStr,
optionNum++, pMsgHdr.field_list[fieldI].data.substr(0, voteOptDescLen),
numVotes, votePercentage);
if (numVotes > 0)
msgBody += " " + CHECK_CHAR;
msgBody += "\r\n";
++tallyIdx;
}
}
if (pollComment.length > 0)
msgBody = pollComment + "\r\n" + msgBody;

nightfox
committed
// If voting is allowed in this sub-board and the current logged-in
// user has not voted on this message, then append some text saying
// how to vote.
var votingAllowed = ((this.subBoardCode != "mail") && (((msg_area.sub[this.subBoardCode].settings & SUB_NOVOTING) == 0)));
if (votingAllowed && !this.HasUserVotedOnMsg(pMsgHdr.number))

nightfox
committed
msgBody += "\1n\r\n\1gTo vote in this poll, press \1w\1h" + this.enhReaderKeys.vote + "\1n\1g now.\r\n";
// If the current logged-in user created this poll, then show the
// users who have voted on it so far.
var msgFromUpper = pMsgHdr.from.toUpperCase();
if ((msgFromUpper == user.name.toUpperCase()) || (msgFromUpper == user.handle.toUpperCase()))
{
// Check all the messages in the messagebase after the current one
// to find poll response messages
if (typeof(msgbase.get_all_msg_headers) === "function")
{
// Get the line from text.dat for writing who voted & when. It
// is a format string and should look something like this:
//"\r\n\1n\1hOn %s, in \1c%s \1n\1c%s\r\n\1h\1m%s voted in your poll: \1n\1h%s\r\n" 787 PollVoteNotice
var userVotedInYourPollText = bbs.text(typeof(PollVoteNotice) != "undefined" ? PollVoteNotice : 787);
// Pass true to get_all_msg_headers() to tell it to return vote messages
// (the parameter was introduced in Synchronet 3.17+)
var tmpHdrs = msgbase.get_all_msg_headers(true);
for (var tmpProp in tmpHdrs)
{
if (tmpHdrs[tmpProp] == null)
continue;
// If this header's thread_back or reply_id matches the poll message
// number, then append the 'user voted' string to the message body.
if ((tmpHdrs[tmpProp].thread_back == pMsgHdr.number) || (tmpHdrs[tmpProp].reply_id == pMsgHdr.id))
{
var msgWrittenLocalTime = msgWrittenTimeToLocalBBSTime(tmpHdrs[tmpProp]);
var voteDate = strftime("%a %b %d %Y %H:%M:%S", msgWrittenLocalTime);
var grpName = "";
var msgbaseCfgName = "";
var msgbase = new MsgBase(this.subBoardCode);
if (msgbase.open())
{
grpName = msgbase.cfg.grp_name;
msgbaseCfgName = msgbase.cfg.name;
msgbase.close();
}
msgBody += format(userVotedInYourPollText, voteDate, grpName, msgbaseCfgName, tmpHdrs[tmpProp].from, pMsgHdr.subject);
}
}
}
}
}
}
else
{
// If the message is UTF8 and the terminal is not UTF8-capable, then convert
// the text to cp437.
msgBody = msgbase.get_msg_body(false, pMsgHdr.number);
if (pMsgHdr.hasOwnProperty("is_utf8") && pMsgHdr.is_utf8)
{
var userConsoleSupportsUTF8 = false;
if (typeof(USER_UTF8) != "undefined")
userConsoleSupportsUTF8 = console.term_supports(USER_UTF8);
if (!userConsoleSupportsUTF8)
msgBody = utf8_cp437(msgBody);
}
// Remove any initial coloring from the message body, which can color the whole message
msgBody = removeInitialColorFromMsgBody(msgBody);
}
msgbase.close();
// Remove any Synchronet pause codes that might exist in the message
msgBody = msgBody.replace("\1p", "").replace("\1P", "");
// If the user is a sysop, this is a moderated message area, and the message
// hasn't been validated, then prepend the message with a message to let the
// sysop now know to validate it.
if (this.subBoardCode != "mail")
{
if (gIsSysop && msg_area.sub[this.subBoardCode].is_moderated && ((pMsgHdr.attr & MSG_VALIDATED) == 0))
{
var validateNotice = "\1n\1h\1yThis is an unvalidated message in a moderated area. Press "
+ this.enhReaderKeys.validateMsg + " to validate it.\r\n\1g";
for (var i = 0; i < 79; ++i)
validateNotice += HORIZONTAL_SINGLE;
validateNotice += "\1n\r\n";
msgBody = validateNotice + msgBody;
}
}
return msgBody;
}
// For the DigDistMsgReader class: Refreshes a message header in one of the
// internal message arrays.
//
// Parameters:
// pMsgNum: The number of the message to replace
function DigDistMsgReader_RefreshMsgHdrInArrays(pMsgNum)
{
var msgbase = new MsgBase(this.subBoardCode);
if (!msgbase.open())
return;
if (this.msgSearchHdrs.hasOwnProperty(this.subBoardCode) &&
(this.msgSearchHdrs[this.subBoardCode].indexed.length > 0))
{
for (var i = 0; i < this.msgSearchHdrs[this.subBoardCode].indexed.length; ++i)
{
if (this.msgSearchHdrs[this.subBoardCode].indexed[i].number == pMsgNum)
{
var newMsgHdr = msgbase.get_msg_header(false, pMsgNum, true);
if (newMsgHdr != null)
this.msgSearchHdrs[this.subBoardCode].indexed[i] = newMsgHdr;
break;
}
}
}
else if (this.hdrsForCurrentSubBoard.length > 0)
{
if (this.hdrsForCurrentSubBoardByMsgNum.hasOwnProperty(pMsgNum))
{
var msgHdrs = msgbase.get_all_msg_headers();
if (msgHdrs.hasOwnProperty(pMsgNum))
{
var msgIdx = this.hdrsForCurrentSubBoardByMsgNum[pMsgNum];
this.hdrsForCurrentSubBoard[msgIdx] = msgHdrs[pMsgNum];
}
}
}
msgbase.close();
}
// For the DigDistMessageReader class: Re-calculates the message list widths and
// format strings
//
// Parameters:
// pMsgNumLen: Optional - Length to use for the message number field. If not specified,
// then this will get the number of messages in the sub-board and use that
// length.
function DigDistMsgReader_RecalcMsgListWidthsAndFormatStrs(pMsgNumLen)
{
// Note: Constructing these strings must be done after reading the configuration
// file in order for the configured colors to be used
this.sMsgListHdrFormatStr = "";
this.sMsgInfoFormatStr = "";
this.sMsgInfoToUserFormatStr = "";
this.sMsgInfoFromUserFormatStr = "";
this.sMsgInfoFormatHighlightStr = "";
this.MSGNUM_LEN = (typeof(pMsgNumLen) == "number" ? pMsgNumLen : this.NumMessages(null, true).toString().length);
if (this.MSGNUM_LEN < 4)
this.MSGNUM_LEN = 4;
this.DATE_LEN = 10; // i.e., YYYY-MM-DD
this.TIME_LEN = 8; // i.e., HH:MM:SS
// Variable field widths: From, to, and subject
this.FROM_LEN = (console.screen_columns * (15/console.screen_columns)).toFixed(0);
this.TO_LEN = (console.screen_columns * (15/console.screen_columns)).toFixed(0);
var colsLeftForSubject = console.screen_columns-this.MSGNUM_LEN-this.DATE_LEN-this.TIME_LEN-this.FROM_LEN-this.TO_LEN-6; // 6 to account for the spaces
this.SUBJ_LEN = (console.screen_columns * (colsLeftForSubject/console.screen_columns)).toFixed(0);
14556
14557
14558
14559
14560
14561
14562
14563
14564
14565
14566
14567
14568
14569
14570
14571
14572
14573
14574
14575
14576
14577
14578
14579
14580
14581
14582
14583
14584
14585
14586
14587
14588
14589
14590
14591
14592
14593
14594
14595
14596
14597
14598
14599
14600
14601
14602
14603
14604
14605
14606
14607
14608
14609
14610
14611
14612
14613
14614
14615
14616
14617
14618
14619
14620
14621
14622
14623
14624
14625
14626
14627
14628
14629
14630
14631
14632
14633
14634
14635
14636
14637
14638
14639
14640
14641
14642
if (this.showScoresInMsgList)
{
this.SUBJ_LEN -= (this.SCORE_LEN + 1);
this.sMsgListHdrFormatStr = "%" + this.MSGNUM_LEN + "s %-" + this.FROM_LEN + "s %-"
+ this.TO_LEN + "s %-" + this.SUBJ_LEN + "s %"
+ this.SCORE_LEN + "s %-" + this.DATE_LEN + "s %-"
+ this.TIME_LEN + "s";
this.sMsgInfoFormatStr = this.colors.msgListMsgNumColor + "%" + this.MSGNUM_LEN + "d%s"
+ this.colors.msgListFromColor + "%-" + this.FROM_LEN + "s "
+ this.colors.msgListToColor + "%-" + this.TO_LEN + "s "
+ this.colors.msgListSubjectColor + "%-" + this.SUBJ_LEN + "s "
+ this.colors.msgListScoreColor + "%" + this.SCORE_LEN + "d "
+ this.colors.msgListDateColor + "%-" + this.DATE_LEN + "s "
+ this.colors.msgListTimeColor + "%-" + this.TIME_LEN + "s";
// Message information format string with colors to use when the message is
// written to the user.
this.sMsgInfoToUserFormatStr = this.colors.msgListToUserMsgNumColor + "%" + this.MSGNUM_LEN + "d%s"
+ this.colors.msgListToUserFromColor
+ "%-" + this.FROM_LEN + "s " + this.colors.msgListToUserToColor + "%-"
+ this.TO_LEN + "s " + this.colors.msgListToUserSubjectColor + "%-"
+ this.SUBJ_LEN + "s " + this.colors.msgListToUserScoreColor + "%"
+ this.SCORE_LEN + "d " + this.colors.msgListToUserDateColor
+ "%-" + this.DATE_LEN + "s " + this.colors.msgListToUserTimeColor
+ "%-" + this.TIME_LEN + "s";
// Message information format string with colors to use when the message is
// from the user.
this.sMsgInfoFromUserFormatStr = this.colors.msgListFromUserMsgNumColor + "%" + this.MSGNUM_LEN + "d%s"
+ this.colors.msgListFromUserFromColor
+ "%-" + this.FROM_LEN + "s " + this.colors.msgListFromUserToColor + "%-"
+ this.TO_LEN + "s " + this.colors.msgListFromUserSubjectColor + "%-"
+ this.SUBJ_LEN + "s " + this.colors.msgListFromUserScoreColor + "%"
+ this.SCORE_LEN + "d " + this.colors.msgListFromUserDateColor
+ "%-" + this.DATE_LEN + "s " + this.colors.msgListFromUserTimeColor
+ "%-" + this.TIME_LEN + "s";
// Highlighted message information line for the message list (used for the
// lightbar interface)
this.sMsgInfoFormatHighlightStr = this.colors.msgListMsgNumHighlightColor
+ "%" + this.MSGNUM_LEN + "d%s"
+ this.colors.msgListFromHighlightColor + "%-" + this.FROM_LEN
+ "s " + this.colors.msgListToHighlightColor + "%-" + this.TO_LEN + "s "
+ this.colors.msgListSubjHighlightColor + "%-" + this.SUBJ_LEN + "s "
+ this.colors.msgListScoreHighlightColor + "%" + this.SCORE_LEN + "d "
+ this.colors.msgListDateHighlightColor + "%-" + this.DATE_LEN + "s "
+ this.colors.msgListTimeHighlightColor + "%-" + this.TIME_LEN + "s";
}
else
{
this.sMsgListHdrFormatStr = "%" + this.MSGNUM_LEN + "s %-" + this.FROM_LEN + "s %-"
+ this.TO_LEN + "s %-" + this.SUBJ_LEN + "s %-"
+ this.DATE_LEN + "s %-" + this.TIME_LEN + "s";
this.sMsgInfoFormatStr = this.colors.msgListMsgNumColor + "%" + this.MSGNUM_LEN + "d%s"
+ this.colors.msgListFromColor + "%-" + this.FROM_LEN + "s "
+ this.colors.msgListToColor + "%-" + this.TO_LEN + "s "
+ this.colors.msgListSubjectColor + "%-" + this.SUBJ_LEN + "s "
+ this.colors.msgListDateColor + "%-" + this.DATE_LEN + "s "
+ this.colors.msgListTimeColor + "%-" + this.TIME_LEN + "s";
// Message information format string with colors to use when the message is
// written to the user.
this.sMsgInfoToUserFormatStr = this.colors.msgListToUserMsgNumColor + "%" + this.MSGNUM_LEN + "d%s"
+ this.colors.msgListToUserFromColor
+ "%-" + this.FROM_LEN + "s " + this.colors.msgListToUserToColor + "%-"
+ this.TO_LEN + "s " + this.colors.msgListToUserSubjectColor + "%-"
+ this.SUBJ_LEN + "s " + this.colors.msgListToUserDateColor
+ "%-" + this.DATE_LEN + "s " + this.colors.msgListToUserTimeColor
+ "%-" + this.TIME_LEN + "s";
// Message information format string with colors to use when the message is
// from the user.
this.sMsgInfoFromUserFormatStr = this.colors.msgListFromUserMsgNumColor + "%" + this.MSGNUM_LEN + "d%s"
+ this.colors.msgListFromUserFromColor
+ "%-" + this.FROM_LEN + "s " + this.colors.msgListFromUserToColor + "%-"
+ this.TO_LEN + "s " + this.colors.msgListFromUserSubjectColor + "%-"
+ this.SUBJ_LEN + "s " + this.colors.msgListFromUserDateColor
+ "%-" + this.DATE_LEN + "s " + this.colors.msgListFromUserTimeColor
+ "%-" + this.TIME_LEN + "s";
// Highlighted message information line for the message list (used for the
// lightbar interface)
this.sMsgInfoFormatHighlightStr = this.colors.msgListMsgNumHighlightColor
+ "%" + this.MSGNUM_LEN + "d%s"
+ this.colors.msgListFromHighlightColor + "%-" + this.FROM_LEN
+ "s " + this.colors.msgListToHighlightColor + "%-" + this.TO_LEN + "s "
+ this.colors.msgListSubjHighlightColor + "%-" + this.SUBJ_LEN + "s "
+ this.colors.msgListDateHighlightColor + "%-" + this.DATE_LEN + "s "
+ this.colors.msgListTimeHighlightColor + "%-" + this.TIME_LEN + "s";
}
// If the user's terminal doesn't support ANSI, then append a newline to
// the end of the header format string (we won't be able to move the cursor).
if (!canDoHighASCIIAndANSI())
this.sMsgListHdrFormatStr += "\r\n";
}
///////////////////////////////////////////////////////////////////////////////////
// Helper functions
// Displays the program information.
function DisplayProgramInfo()
{
displayTextWithLineBelow("Digital Distortion Message Reader", true, "\1n\1c\1h", "\1k\1h")
console.center("\1n\1cVersion \1g" + READER_VERSION + " \1w\1h(\1b" + READER_DATE + "\1w)");
console.crlf();
}
// This function returns an array of default colors used in the
// DigDistMessageReader class.
function getDefaultColors()
{
var colorObj = new Object();
// Header line: "Current msg group:"
colorObj.msgListHeaderMsgGroupTextColor = "\1n\1" + "4\1c"; // Normal cyan on blue background
//colorObj.msgListHeaderMsgGroupTextColor = "\1n\1" + "4\1w"; // Normal white on blue background
// Header line: Message group name
colorObj.msgListHeaderMsgGroupNameColor = "\1h\1c"; // High cyan
//colorObj.msgListHeaderMsgGroupNameColor = "\1h\1w"; // High white
// Header line: "Current sub-board:"
colorObj.msgListHeaderSubBoardTextColor = "\1n\1" + "4\1c"; // Normal cyan on blue background
//colorObj.msgListHeaderSubBoardTextColor = "\1n\1" + "4\1w"; // Normal white on blue background
// Header line: Message sub-board name
colorObj.msgListHeaderMsgSubBoardName = "\1h\1c"; // High cyan
//colorObj.msgListHeaderMsgSubBoardName = "\1h\1w"; // High white
// Line with column headers
//colorObj.msgListColHeader = "\1h\1w"; // High white (keep blue background)
colorObj.msgListColHeader = "\1n\1h\1w"; // High white on black background
//colorObj.msgListColHeader = "\1h\1c"; // High cyan (keep blue background)
//colorObj.msgListColHeader = "\1" + "4\1h\1y"; // High yellow (keep blue background)
// Message list information
colorObj.msgListMsgNumColor = "\1n\1h\1y";
colorObj.msgListFromColor = "\1n\1c";
colorObj.msgListToColor = "\1n\1c";
colorObj.msgListSubjectColor = "\1n\1c";
colorObj.msgListScoreColor = "\1n\1c";
colorObj.msgListDateColor = "\1h\1b";
colorObj.msgListTimeColor = "\1h\1b";
// Message information for messages written to the user
colorObj.msgListToUserMsgNumColor = "\1n\1h\1y";
colorObj.msgListToUserFromColor = "\1h\1g";
colorObj.msgListToUserToColor = "\1h\1g";
colorObj.msgListToUserSubjectColor = "\1h\1g";
colorObj.msgListToUserScoreColor = "\1h\1g";
colorObj.msgListToUserDateColor = "\1h\1b";
colorObj.msgListToUserTimeColor = "\1h\1b";
// Message information for messages from the user
colorObj.msgListFromUserMsgNumColor = "\1n\1h\1y";
colorObj.msgListFromUserFromColor = "\1n\1c";
colorObj.msgListFromUserToColor = "\1n\1c";
colorObj.msgListFromUserSubjectColor = "\1n\1c";
colorObj.msgListFromUserScoreColor = "\1n\1c";
colorObj.msgListFromUserDateColor = "\1h\1b";
colorObj.msgListFromUserTimeColor = "\1h\1b";
// Message list highlight colors
colorObj.msgListHighlightBkgColor = "\1" + "4"; // Background
colorObj.msgListMsgNumHighlightColor = "\1h\1y";
colorObj.msgListFromHighlightColor = "\1h\1c";
colorObj.msgListToHighlightColor = "\1h\1c";
colorObj.msgListSubjHighlightColor = "\1h\1c";
colorObj.msgListScoreHighlightColor = "\1h\1c";
colorObj.msgListDateHighlightColor = "\1h\1w";
colorObj.msgListTimeHighlightColor = "\1h\1w";
// Lightbar message list help line colors
colorObj.lightbarMsgListHelpLineBkgColor = "\1" + "7"; // Background
colorObj.lightbarMsgListHelpLineGeneralColor = "\1b";
colorObj.lightbarMsgListHelpLineHotkeyColor = "\1r";
colorObj.lightbarMsgListHelpLineParenColor = "\1m";
// Continue prompt colors
colorObj.tradInterfaceContPromptMainColor = "\1n\1g"; // Main text color
colorObj.tradInterfaceContPromptHotkeyColor = "\1h\1c"; // Hotkey color
colorObj.tradInterfaceContPromptUserInputColor = "\1h\1g"; // User input color
// Message body color
colorObj.msgBodyColor = "\1n\1w";
// Read message confirmation colors
colorObj.readMsgConfirmColor = "\1n\1c";
colorObj.readMsgConfirmNumberColor = "\1h\1c";
// Prompt for continuing to list messages after reading a message
colorObj.afterReadMsg_ListMorePromptColor = "\1n\1c";
// Help screen text color
colorObj.tradInterfaceHelpScreenColor = "\1n\1h\1w";
// Colors for choosing a message group & sub-board
colorObj.areaChooserMsgAreaNumColor = "\1n\1w\1h";
colorObj.areaChooserMsgAreaDescColor = "\1n\1c";
colorObj.areaChooserMsgAreaNumItemsColor = "\1b\1h";
colorObj.areaChooserMsgAreaHeaderColor = "\1n\1y\1h";
colorObj.areaChooserSubBoardHeaderColor = "\1n\1g";
colorObj.areaChooserMsgAreaMarkColor = "\1g\1h";
colorObj.areaChooserMsgAreaLatestDateColor = "\1n\1g";
colorObj.areaChooserMsgAreaLatestTimeColor = "\1n\1m";
// Highlighted colors (for lightbar mode)
colorObj.areaChooserMsgAreaBkgHighlightColor = "\1" + "4"; // Blue background
colorObj.areaChooserMsgAreaNumHighlightColor = "\1w\1h";
colorObj.areaChooserMsgAreaDescHighlightColor = "\1c";
colorObj.areaChooserMsgAreaDateHighlightColor = "\1w\1h";
colorObj.areaChooserMsgAreaTimeHighlightColor = "\1w\1h";
colorObj.areaChooserMsgAreaNumItemsHighlightColor = "\1w\1h";
// Lightbar area chooser help line
colorObj.lightbarAreaChooserHelpLineBkgColor = "\1" + "7"; // Background
colorObj.lightbarAreaChooserHelpLineGeneralColor = "\1b";
colorObj.lightbarAreaChooserHelpLineHotkeyColor = "\1r";
colorObj.lightbarAreaChooserHelpLineParenColor = "\1m";
// Scrollbar background and scroll block colors (for the enhanced
// message reader interface)
colorObj.scrollbarBGColor = "\1n\1h\1k";
colorObj.scrollbarScrollBlockColor = "\1n\1h\1w";
// Color for the line drawn in the 2nd to last line of the message
// area in the enhanced reader mode before a prompt
colorObj.enhReaderPromptSepLineColor = "\1n\1h\1g";
// Colors for the enhanced reader help line
colorObj.enhReaderHelpLineBkgColor = "\1" + "7";
colorObj.enhReaderHelpLineGeneralColor = "\1b";
colorObj.enhReaderHelpLineHotkeyColor = "\1r";
colorObj.enhReaderHelpLineParenColor = "\1m";
// Message header line colors
colorObj.hdrLineLabelColor = "\1n\1c";
colorObj.hdrLineValueColor = "\1n\1b\1h";
// Selected message marker color
colorObj.selectedMsgMarkColor = "\1n\1w\1h";
return colorObj;
14788
14789
14790
14791
14792
14793
14794
14795
14796
14797
14798
14799
14800
14801
14802
14803
14804
14805
14806
14807
14808
14809
14810
14811
14812
14813
14814
14815
14816
14817
14818
14819
14820
14821
14822
14823
14824
14825
14826
14827
14828
14829
14830
14831
14832
14833
14834
14835
14836
14837
14838
14839
14840
14841
14842
14843
14844
14845
14846
14847
14848
14849
14850
14851
14852
14853
14854
14855
14856
14857
14858
14859
14860
14861
14862
14863
14864
14865
14866
14867
14868
14869
14870
14871
14872
14873
14874
14875
14876
}
// This function returns the month number (1-based) from a capitalized
// month name.
//
// Parameters:
// pMonthName: The name of the month
//
// Return value: The number of the month (1-12).
function getMonthNum(pMonthName)
{
var monthNum = 1;
if (pMonthName.substr(0, 3) == "Jan")
monthNum = 1;
else if (pMonthName.substr(0, 3) == "Feb")
monthNum = 2;
else if (pMonthName.substr(0, 3) == "Mar")
monthNum = 3;
else if (pMonthName.substr(0, 3) == "Apr")
monthNum = 4;
else if (pMonthName.substr(0, 3) == "May")
monthNum = 5;
else if (pMonthName.substr(0, 3) == "Jun")
monthNum = 6;
else if (pMonthName.substr(0, 3) == "Jul")
monthNum = 7;
else if (pMonthName.substr(0, 3) == "Aug")
monthNum = 8;
else if (pMonthName.substr(0, 3) == "Sep")
monthNum = 9;
else if (pMonthName.substr(0, 3) == "Oct")
monthNum = 10;
else if (pMonthName.substr(0, 3) == "Nov")
monthNum = 11;
else if (pMonthName.substr(0, 3) == "Dec")
monthNum = 12;
return monthNum;
}
// Clears each line from a given line to the end of the screen.
//
// Parameters:
// pStartLineNum: The line number to start at (1-based)
function clearToEOS(pStartLineNum)
{
if (typeof(pStartLineNum) == "undefined")
return;
if (pStartLineNum == null)
return;
for (var lineNum = pStartLineNum; lineNum <= console.screen_rows; ++lineNum)
{
console.gotoxy(1, lineNum);
console.clearline();
}
}
// Returns the number of messages in a sub-board.
//
// Parameters:
// pSubBoardCode: The sub-board code (i.e., from bbs.cursub_code)
//
// Return value: The number of messages in the sub-board, or 0
// if the sub-board could not be opened.
function numMessages(pSubBoardCode)
{
var messageCount = 0;
var myMsgbase = new MsgBase(pSubBoardCode);
if (myMsgbase.open())
messageCount = myMsgbase.total_msgs;
myMsgbase.close();
myMsgbase = null;
return messageCount;
}
// Removes multiple, leading, and/or trailing spaces
// The search & replace regular expressions used in this
// function came from the following URL:
// http://qodo.co.uk/blog/javascript-trim-leading-and-trailing-spaces
//
// Parameters:
// pString: The string to trim
// pLeading: Whether or not to trim leading spaces (optional, defaults to true)
// pMultiple: Whether or not to trim multiple spaces (optional, defaults to true)
// pTrailing: Whether or not to trim trailing spaces (optional, defaults to true)

nightfox
committed
//
// Return value: The string with whitespace trimmed
14879
14880
14881
14882
14883
14884
14885
14886
14887
14888
14889
14890
14891
14892
14893
14894
14895
14896
14897
14898
14899
14900
14901
14902
14903
14904
14905
14906
14907
14908
14909
14910
14911
14912
14913
14914
14915
14916
14917
14918
14919
14920
14921
14922
14923
14924
14925
14926
14927
14928
function trimSpaces(pString, pLeading, pMultiple, pTrailing)
{
var leading = true;
var multiple = true;
var trailing = true;
if(typeof(pLeading) != "undefined")
leading = pLeading;
if(typeof(pMultiple) != "undefined")
multiple = pMultiple;
if(typeof(pTrailing) != "undefined")
trailing = pTrailing;
// To remove both leading & trailing spaces:
//pString = pString.replace(/(^\s*)|(\s*$)/gi,"");
if (leading)
pString = pString.replace(/(^\s*)/gi,"");
if (multiple)
pString = pString.replace(/[ ]{2,}/gi," ");
if (trailing)
pString = pString.replace(/(\s*$)/gi,"");
return pString;
}
// Returns whether an internal sub-board code is valid.
//
// Parameters:
// pSubBoardCode: The internal sub-board code to test
//
// Return value: Boolean - Whether or not the given internal code is a valid
// sub-board code
function subBoardCodeIsValid(pSubBoardCode)
{
return ((pSubBoardCode == "mail") || (typeof(msg_area.sub[pSubBoardCode]) == "object"))
}
// Displays some text with a solid horizontal line on the next line.
//
// Parameters:
// pText: The text to display
// pCenter: Whether or not to center the text. Optional; defaults
// to false.
// pTextColor: The color to use for the text. Optional; by default,
// normal white will be used.
// pLineColor: The color to use for the line underneath the text.
// Optional; by default, bright black will be used.
function displayTextWithLineBelow(pText, pCenter, pTextColor, pLineColor)
{
var centerText = (typeof(pCenter) == "boolean" ? pCenter : false);
var textColor = (typeof(pTextColor) == "string" ? pTextColor : "\1n\1w");
var lineColor = (typeof(pLineColor) == "string" ? pLineColor : "\1n\1k\1h");
14932
14933
14934
14935
14936
14937
14938
14939
14940
14941
14942
14943
14944
14945
14946
14947
14948
14949
14950
14951
// Output the text and a solid line on the next line.
if (centerText)
{
console.center(textColor + pText);
var solidLine = "";
var textLength = console.strlen(pText);
for (var i = 0; i < textLength; ++i)
solidLine += "Ä";
console.center(lineColor + solidLine);
}
else
{
console.print(textColor + pText);
console.crlf();
console.print(lineColor);
var textLength = console.strlen(pText);
for (var i = 0; i < textLength; ++i)
console.print("Ä");
console.crlf();
}
14952
14953
14954
14955
14956
14957
14958
14959
14960
14961
14962
14963
14964
14965
14966
14967
14968
14969
14970
14971
14972
14973
14974
14975
14976
14977
14978
14979
14980
14981
14982
14983
14984
14985
14986
14987
14988
14989
14990
14991
14992
14993
14994
14995
14996
14997
14998
14999
15000
}
// Returns whether the Synchronet compile date is at least May 12, 2013. That
// was when Digital Man's change to make bbs.msg_number work when a script is
// running first went into the Synchronet daily builds.
function compileDateAtLeast2013_05_12()
{
// system.compiled_when is in the following format:
// May 12 2013 05:02
var compileDateParts = system.compiled_when.split(" ");
if (compileDateParts.length < 4)
return false;
// Convert the month to a 1-based number
var compileMonth = 0;
if (/^Jan/.test(compileDateParts[0]))
compileMonth = 1;
else if (/^Feb/.test(compileDateParts[0]))
compileMonth = 2;
else if (/^Mar/.test(compileDateParts[0]))
compileMonth = 3;
else if (/^Apr/.test(compileDateParts[0]))
compileMonth = 4;
else if (/^May/.test(compileDateParts[0]))
compileMonth = 5;
else if (/^Jun/.test(compileDateParts[0]))
compileMonth = 6;
else if (/^Jul/.test(compileDateParts[0]))
compileMonth = 7;
else if (/^Aug/.test(compileDateParts[0]))
compileMonth = 8;
else if (/^Sep/.test(compileDateParts[0]))
compileMonth = 9;
else if (/^Oct/.test(compileDateParts[0]))
compileMonth = 10;
else if (/^Nov/.test(compileDateParts[0]))
compileMonth = 11;
else if (/^Dec/.test(compileDateParts[0]))
compileMonth = 12;
// Get the compileDay and compileYear as numeric variables
var compileDay = +compileDateParts[1];
var compileYear = +compileDateParts[2];
// Determine if the compile date is at least 2013-05-12
var compileDateIsAtLeastMin = true;
if (compileYear > 2013)
compileDateIsAtLeastMin = true;