Newer
Older
{
retObj.errorMsg = "Unable to open the sub-board";
return retObj;
}
}
retObj.msgText = word_wrap(msgBody, console.screen_columns - 1, true);
var msgTextAltered = retObj.msgText; // Will alter the message text, but not yet
// Only interpret @-codes if the user is reading personal email. There
// are many @-codes that do some action such as move the cursor, execute a
// script, etc., and I don't want users on message networks to do anything
// malicious to users on other BBSes.
if (this.readingPersonalEmail)
msgTextAltered = replaceAtCodesInStr(msgTextAltered); // Or this.ParseMsgAtCodes(msgTextAltered, pMsgHdr) to replace only some @ codes
msgTextAltered = msgTextAltered.replace(/\t/g, this.tabReplacementText);
// Convert other BBS color codes to Synchronet attribute codes if the settings
// to do so are enabled.
msgTextAltered = convertAttrsToSyncPerSysCfg(msgTextAltered, false);
12019
12020
12021
12022
12023
12024
12025
12026
12027
12028
12029
12030
12031
12032
12033
12034
12035
12036
12037
12038
12039
12040
12041
12042
12043
12044
// If this is a message with a "By: <name> to <name>" and a date, then
// sometimes such a message might have enter characters (ASCII 13), which
// can mess up the display of the message, so remove enter characters
// from the beginning of the message.
var msgTextWithoutAttrs = strip_ctrl(msgTextAltered);
var fromToSearchStr = "By: " + pMsgHdr.from + " to " + pMsgHdr.to;
var toFromSearchStr = "By: " + pMsgHdr.to + " to " + pMsgHdr.from;
var fromToStrIdx = msgTextWithoutAttrs.indexOf(fromToSearchStr);
var toFromStrIdx = msgTextWithoutAttrs.indexOf(toFromSearchStr);
var strIdx = -1;
if (fromToStrIdx > -1)
strIdx = fromToStrIdx;
else if (toFromStrIdx > -1)
strIdx = toFromStrIdx;
if (strIdx > -1)
{
// " on Mon Feb 13 2017 01:00 pm " // 29 characters long
strIdx += toFromSearchStr.length + 29 + 37; // 37: Extra room for Synchronet attribute codes
// Remove enter characters from the beginning of the message
var tmpStr = msgTextAltered.substring(0, strIdx).replace(ascii(13), "");
msgTextAltered = tmpStr + msgTextAltered.substr(strIdx);
// To remove the "By: <name> to <name> on <date>" lines altogether:
//msgTextAltered = msgTextAltered.substr(strIdx);
}
12045
12046
12047
12048
12049
12050
12051
12052
12053
12054
12055
12056
12057
12058
12059
12060
12061
12062
12063
12064
12065
12066
12067
12068
12069
12070
12071
12072
12073
12074
12075
12076
12077
12078
12079
12080
12081
12082
var wordWrapTheMsgText = true;
if (typeof(pWordWrap) == "boolean")
wordWrapTheMsgText = pWordWrap;
if (wordWrapTheMsgText)
{
// Wrap the text to fit into the available message area.
// Note: In Synchronet 3.15 (and some beta builds of 3.16), there seemed to
// be a bug in the word_wrap() function where the word wrap length in Linux
// was one less than Windows, so if the BBS is running 3.15 or earlier of
// Synchronet, add 1 to the word wrap length if running in Linux.
var textWrapLen = this.msgAreaWidth;
if (system.version_num <= 31500)
textWrapLen = gRunningInWindows ? this.msgAreaWidth : this.msgAreaWidth + 1;
var msgTextWrapped = word_wrap(msgTextAltered, textWrapLen);
retObj.messageLines = lfexpand(msgTextWrapped).split("\r\n");
// Go through the message lines and trim them to ensure they'll easily fit
// in the message display area without having to trim them later. (Note:
// this is okay to do since we're only using messageLines to display the
// message on the screen; messageLines isn't used for quoting/replying).
for (var msgLnIdx = 0; msgLnIdx < retObj.messageLines.length; ++msgLnIdx)
retObj.messageLines[msgLnIdx] = shortenStrWithAttrCodes(retObj.messageLines[msgLnIdx], this.msgAreaWidth);
// Set up some variables for displaying the message
retObj.topMsgLineIdxForLastPage = retObj.messageLines.length - this.msgAreaHeight;
if (retObj.topMsgLineIdxForLastPage < 0)
retObj.topMsgLineIdxForLastPage = 0;
// Variables for the scrollbar to show the fraction of the message shown
retObj.msgFractionShown = this.msgAreaHeight / retObj.messageLines.length;
if (retObj.msgFractionShown > 1)
retObj.msgFractionShown = 1.0;
retObj.numSolidScrollBlocks = Math.floor(this.msgAreaHeight * retObj.msgFractionShown);
if (retObj.numSolidScrollBlocks == 0)
retObj.numSolidScrollBlocks = 1;
}
else
{
retObj.messageLines = [];
retObj.messageLines.push(msgTextAltered);
}
12083
12084
12085
12086
12087
12088
12089
12090
12091
12092
12093
12094
12095
12096
12097
12098
12099
12100
retObj.numNonSolidScrollBlocks = this.msgAreaHeight - retObj.numSolidScrollBlocks;
retObj.solidBlockStartRow = this.msgAreaTop;
return retObj;
}
// For the DigDistMsgReader class: Returns the index of the last read message in
// the current message area. If reading personal email, this will look at the
// search results. Otherwise, this will use the sub-board's last_read pointer.
// If there is no last read message or if there is a problem getting the last read
// message index, this method will return -1.
//
// Parameters:
// pMailStartFromFirst: Optional boolean - Whether or not to start from the
// first message (rather than from the last message) if
// reading personal email. Will stop looking at the first
// unread message. Defaults to false.
//
// Return value: An object containing the following properties:
// lastReadMsgIdx: The index of the last read message in the current message area
// lastReadMsgNum: The number of the last read message in the current message area
function DigDistMsgReader_GetLastReadMsgIdxAndNum(pMailStartFromFirst)
{
var retObj = {
lastReadMsgIdx: -1,
lastReadMsgNum: -1
};
if (this.readingPersonalEmail)
{
if (this.SearchingAndResultObjsDefinedForCurSub())
{
var startFromFirst = (typeof(pMailStartFromFirst) == "boolean" ? pMailStartFromFirst : false);
if (startFromFirst)
{
for (var idx = 0; idx < this.msgSearchHdrs[this.subBoardCode].indexed.length; ++idx)
{
if ((this.msgSearchHdrs[this.subBoardCode].indexed[idx].attr & MSG_READ) == MSG_READ)
{
retObj.lastReadMsgIdx = idx;
retObj.lastReadMsgNum = this.msgSearchHdrs[this.subBoardCode].indexed[idx].number;
}
else
break;
}
}
else
{
for (var idx = this.msgSearchHdrs[this.subBoardCode].indexed.length-1; idx >= 0; --idx)
{
if ((this.msgSearchHdrs[this.subBoardCode].indexed[idx].attr & MSG_READ) == MSG_READ)
{
retObj.lastReadMsgIdx = idx;
retObj.lastReadMsgNum = this.msgSearchHdrs[this.subBoardCode].indexed[idx].number;
break;
}
}
}
// Sanity checking for retObj.lastReadMsgIdx (note: this function should return -1 if
// there is no last read message).
if (retObj.lastReadMsgIdx >= this.msgSearchHdrs[this.subBoardCode].indexed.length)
{
retObj.lastReadMsgIdx = this.msgSearchHdrs[this.subBoardCode].indexed.length - 1;
retObj.lastReadMsgNum = this.msgSearchHdrs[this.subBoardCode].indexed[retObj.lastReadMsgIdx].number;
}
}
}
else
{
//retObj.lastReadMsgIdx = this.AbsMsgNumToIdx(msg_area.sub[this.subBoardCode].last_read);
retObj.lastReadMsgIdx = this.GetMsgIdx(msg_area.sub[this.subBoardCode].last_read);
retObj.lastReadMsgNum = msg_area.sub[this.subBoardCode].last_read;
/*
this.hdrsForCurrentSubBoard = [];
// hdrsForCurrentSubBoardByMsgNum is an object that maps absolute message numbers
// to their index to hdrsForCurrentSubBoard
this.hdrsForCurrentSubBoardByMsgNum = {};
*/
// Sanity checking for retObj.lastReadMsgIdx (note: this function should return -1 if
// there is no last read message).
var msgbase = new MsgBase(this.subBoardCode);
if (msgbase.open())
{
// If retObj.lastReadMsgIdx is -1, as a result of GetMsgIdx(), then see what the last read
// message index is according to the Synchronet message base. If
// this.hdrsForCurrentSubBoard.length has been populated, then if the last
// message index according to Synchronet is greater than that, then set the
// message index to the last index in this.hdrsForCurrentSubBoard.length.
if (retObj.lastReadMsgIdx == -1)
{
var msgIdxAccordingToMsgbase = absMsgNumToIdx(msgbase, msg_area.sub[this.subBoardCode].last_read);
if ((this.hdrsForCurrentSubBoard.length > 0) && (msgIdxAccordingToMsgbase >= this.hdrsForCurrentSubBoard.length))
{
retObj.lastReadMsgIdx = this.hdrsForCurrentSubBoard.length - 1;
retObj.lastReadMsgNum = this.hdrsForCurrentSubBoard[retObj.lastReadMsgIdx].number;
}
}
//if (retObj.lastReadMsgIdx >= msgbase.total_msgs)
// retObj.lastReadMsgIdx = msgbase.total_msgs - 1;
// TODO: Is this code right? Modified 3/24/2015 to replace
// the above 2 commented lines.
if ((retObj.lastReadMsgIdx < 0) || (retObj.lastReadMsgIdx >= msgbase.total_msgs))
12185
12186
12187
12188
12189
12190
12191
12192
12193
12194
12195
12196
12197
12198
12199
12200
12201
12202
{
// Look for the first message not marked as deleted
var nonDeletedMsgIdx = this.FindNextNonDeletedMsgIdx(0, true);
// If a non-deleted message was found, then set the last read
// pointer to it.
if (nonDeletedMsgIdx > -1)
{
var newLastRead = this.IdxToAbsMsgNum(nonDeletedMsgIdx);
if (newLastRead > -1)
msg_area.sub[this.subBoardCode].last_read = newLastRead;
else
msg_area.sub[this.subBoardCode].last_read = 0;
}
else
msg_area.sub[this.subBoardCode].last_read = 0;
}
}
}
return retObj;
}
// For the DigDistMsgReader class: Returns the index of the message pointed to
// by the scan pointer in the current sub-board. If reading personal email or
// if the message base isn't open, this will return 0. If the scan pointer is
// 0 or if the messagebase is open and the scan pointer is invalid, this will
// return -1.
function DigDistMsgReader_GetScanPtrMsgIdx()
{
if (this.readingPersonalEmail)
return 0;
if (msg_area.sub[this.subBoardCode].scan_ptr == 0)
return -1;
// If the user's scan pointer is a crazy value, that could be because
// the user hasn't read messages in the sub-board yet. In that case,
// just use 0. Otherwise, get the user's scan pointer message index.
var msgIdx = 0;
// If pMsgNum is 4294967295 (0xffffffff, or ~0), that is a special value
// for the user's scan_ptr meaning it should point to the latest message
// in the messagebase.
if (msg_area.sub[this.subBoardCode].scan_ptr != 0xffffffff)
msgIdx = this.GetMsgIdx(msg_area.sub[this.subBoardCode].scan_ptr);
// Sanity checking for msgIdx
var msgbase = new MsgBase(this.subBoardCode);
if (msgbase.open())
{
if ((msgIdx < 0) || (msgIdx >= msgbase.total_msgs) || (msg_area.sub[this.subBoardCode].scan_ptr == 0xffffffff))
{
msgIdx = -1;
// Look for the first message not marked as deleted
var nonDeletedMsgIdx = this.FindNextNonDeletedMsgIdx(0, true);
// If a non-deleted message was found, then set the scan pointer to it.
if (nonDeletedMsgIdx > -1)
{
var newLastRead = this.IdxToAbsMsgNum(nonDeletedMsgIdx);
if (newLastRead > -1)
msg_area.sub[this.subBoardCode].scan_ptr = newLastRead;
else
msg_area.sub[this.subBoardCode].scan_ptr = 0;
}
else
msg_area.sub[this.subBoardCode].scan_ptr = 0;
}
msgbase.close();
12249
12250
12251
12252
12253
12254
12255
12256
12257
12258
12259
12260
12261
12262
12263
12264
12265
12266
12267
12268
12269
12270
12271
12272
12273
12274
12275
12276
12277
12278
12279
12280
12281
12282
12283
12284
12285
12286
12287
12288
12289
12290
12291
12292
12293
}
return msgIdx;
}
// For the DigDistMsgReader class: Returns whether there is a search specified
// (according to this.searchType) and the search result objects are defined for
// the current sub-board (as specified by this.subBoardCode).
//
// Return value: Boolean - Whether or not there is a search specified and the
// search result objects are defined for the current sub-board
// (as specified by this.subBoardCode).
function DigDistMsgReader_SearchingAndResultObjsDefinedForCurSub()
{
return (this.SearchTypePopulatesSearchResults() && (this.msgSearchHdrs != null) &&
this.msgSearchHdrs.hasOwnProperty(this.subBoardCode) &&
(typeof(this.msgSearchHdrs[this.subBoardCode]) == "object") &&
(typeof(this.msgSearchHdrs[this.subBoardCode].indexed) != "undefined"));
}
// For the DigDistMsgReader class: Removes a message header from the search
// results array for the current sub-board.
//
// Parameters:
// pMsgIdx: The index of the message header to remove (in the indexed messages,
// not necessarily the actual message offset in the messagebase)
function DigDistMsgReader_RemoveFromSearchResults(pMsgIdx)
{
if (typeof(pMsgIdx) != "number")
return;
if ((typeof(this.msgSearchHdrs) == "object") &&
this.msgSearchHdrs.hasOwnProperty(this.subBoardCode) &&
(typeof(this.msgSearchHdrs[this.subBoardCode].indexed) != "undefined"))
{
if ((pMsgIdx >= 0) && (pMsgIdx < this.msgSearchHdrs[this.subBoardCode].indexed.length))
this.msgSearchHdrs[this.subBoardCode].indexed.splice(pMsgIdx, 1);
}
}
// For the DigDistMsgReader class: Looks for the next message in the thread of
// a given message (by its header).
//
// Paramters:
// pMsgHdr: A message header object - The next message in the thread will be
// searched starting from this message

nightfox
committed
// pThreadType: The type of threading to use. Can be THREAD_BY_ID, THREAD_BY_TITLE,
// THREAD_BY_AUTHOR, or THREAD_BY_TO_USER.
// pPositionCursorForStatus: Optional boolean - Whether or not to move the cursor
// to the bottom row before outputting status messages.
// Defaults to false.
//
// Return value: The offset (index) of the next message thread, or -1 if none
// was found.

nightfox
committed
function DigDistMsgReader_FindThreadNextOffset(pMsgHdr, pThreadType, pPositionCursorForStatus)
{
if ((pMsgHdr == null) || (typeof(pMsgHdr) != "object"))
return -1;
var newMsgOffset = -1;

nightfox
committed
switch (pThreadType)
{

nightfox
committed
case THREAD_BY_ID:
default:
// The thread_id field was introduced in Synchronet 3.16. So, if
// the Synchronet version is 3.16 or higher and the message header
// has a thread_id field, then look for the next message with the
// same thread ID. If the Synchronet version is below 3.16 or there
// is no thread ID, then fall back to using the header's thread_next,
// if it exists.
if ((system.version_num >= 31600) && (typeof(pMsgHdr.thread_id) == "number"))
{
// Look for the next message with the same thread ID.
// Write "Searching.." in case searching takes a while.
console.print("\x01n");
if (pPositionCursorForStatus)
{
console.gotoxy(1, console.screen_rows);
console.cleartoeol();
console.gotoxy(this.msgAreaLeft, console.screen_rows);
}
console.print("\x01h\x01ySearching\x01i...\x01n");
// Look for the next message in the thread
var nextMsgOffset = -1;
var numOfMessages = this.NumMessages();
/*
if (pMsgHdr.offset < numOfMessages - 1)
{
var nextMsgHdr;
for (var messageIdx = pMsgHdr.offset+1; (messageIdx < numOfMessages) && (nextMsgOffset == -1); ++messageIdx)
{
nextMsgHdr = this.GetMsgHdrByIdx(messageIdx);
if (((nextMsgHdr.attr & MSG_DELETE) == 0) && (typeof(nextMsgHdr.thread_id) == "number") && (nextMsgHdr.thread_id == pMsgHdr.thread_id))
nextMsgOffset = nextMsgHdr.offset;
}
}
*/
if (this.GetMsgIdx(pMsgHdr.number) < numOfMessages - 1)
{
var nextMsgHdr;
for (var messageIdx = this.GetMsgIdx(pMsgHdr.number)+1; (messageIdx < numOfMessages) && (nextMsgOffset == -1); ++messageIdx)
{
nextMsgHdr = this.GetMsgHdrByIdx(messageIdx);
if (((nextMsgHdr.attr & MSG_DELETE) == 0) && (typeof(nextMsgHdr.thread_id) == "number") && (nextMsgHdr.thread_id == pMsgHdr.thread_id))
{
//nextMsgOffset = nextMsgHdr.offset;
nextMsgOffset = this.GetMsgIdx(nextMsgHdr.number);
}
}
}
if (nextMsgOffset > -1)
newMsgOffset = nextMsgOffset;
}
// Fall back to thread_next if the Synchronet version is below 3.16 or there is
// no thread_id field in the header
else if ((typeof(pMsgHdr.thread_next) == "number") && (pMsgHdr.thread_next > 0))

nightfox
committed
{
//newMsgOffset = this.AbsMsgNumToIdx(pMsgHdr.thread_next);
newMsgOffset = this.GetMsgIdx(pMsgHdr.thread_next);
}

nightfox
committed
break;
case THREAD_BY_TITLE:
case THREAD_BY_AUTHOR:
case THREAD_BY_TO_USER:
// Title (subject) searching will look for the subject anywhere in the
// other messages' subjects (not a fully exact subject match), so if
// the message subject is blank, we won't want to do the search.
var doSearch = true;
if ((pThreadType == THREAD_BY_TITLE) && (pMsgHdr.subject.length == 0))
doSearch = false;
if (doSearch)
{

nightfox
committed
12381
12382
12383
12384
12385
12386
12387
12388
12389
12390
12391
12392
12393
12394
12395
12396
12397
12398
12399
12400
12401
12402
12403
12404
12405
12406
12407
12408
12409
12410
12411
12412
12413
12414
12415
12416
12417
12418
var subjUppercase = "";
var fromNameUppercase = "";
var toNameUppercase = "";
// Set up a message header matching function, depending on
// which field of the header we want to match
var msgHdrMatch;
if (pThreadType == THREAD_BY_TITLE)
{
subjUppercase = pMsgHdr.subject.toUpperCase();
// Remove any leading instances of "RE:" from the subject
while (/^RE:/.test(subjUppercase))
subjUppercase = subjUppercase.substr(3);
while (/^RE: /.test(subjUppercase))
subjUppercase = subjUppercase.substr(4);
// Remove any leading & trailing whitespace from the subject
subjUppercase = trimSpaces(subjUppercase, true, true, true);
msgHdrMatch = function(pMsgHdr) {
return (((pMsgHdr.attr & MSG_DELETE) == 0) && (pMsgHdr.subject.toUpperCase().indexOf(subjUppercase, 0) > -1));
};
}
else if (pThreadType == THREAD_BY_AUTHOR)
{
fromNameUppercase = pMsgHdr.from.toUpperCase();
msgHdrMatch = function(pMsgHdr) {
return (((pMsgHdr.attr & MSG_DELETE) == 0) && (pMsgHdr.from.toUpperCase() == fromNameUppercase));
};
}
else if (pThreadType == THREAD_BY_TO_USER)
{
toNameUppercase = pMsgHdr.to.toUpperCase();
msgHdrMatch = function(pMsgHdr) {
return (((pMsgHdr.attr & MSG_DELETE) == 0) && (pMsgHdr.to.toUpperCase() == toNameUppercase));
};
}
// Perform the search
// Write "Searching.." in case searching takes a while.
console.print("\x01n");

nightfox
committed
if (pPositionCursorForStatus)
{
console.gotoxy(1, console.screen_rows);
console.cleartoeol();
console.gotoxy(this.msgAreaLeft, console.screen_rows);
}
console.print("\x01h\x01ySearching\x01i...\x01n");

nightfox
committed
// Look for the next message that contains the given message's subject
var nextMsgOffset = -1;
var numOfMessages = this.NumMessages();
/*

nightfox
committed
if (pMsgHdr.offset < numOfMessages - 1)
{

nightfox
committed
var nextMsgHdr;
for (var messageIdx = pMsgHdr.offset+1; (messageIdx < numOfMessages) && (nextMsgOffset == -1); ++messageIdx)
{
nextMsgHdr = this.GetMsgHdrByIdx(messageIdx);
if (msgHdrMatch(nextMsgHdr))
nextMsgOffset = nextMsgHdr.offset;
}
}
*/
if (this.GetMsgIdx(pMsgHdr.number) < numOfMessages - 1)
{
var nextMsgHdr;
for (var messageIdx = this.GetMsgIdx(pMsgHdr.number)+1; (messageIdx < numOfMessages) && (nextMsgOffset == -1); ++messageIdx)
{
nextMsgHdr = this.GetMsgHdrByIdx(messageIdx);
if (msgHdrMatch(nextMsgHdr))
{
//nextMsgOffset = nextMsgHdr.offset;
nextMsgOffset = this.GetMsgIdx(nextMsgHdr.number);
}
}
}

nightfox
committed
if (nextMsgOffset > -1)
newMsgOffset = nextMsgOffset;
}

nightfox
committed
break;
}
// If no messages were found, then output a message to say so with a momentary pause.
if (newMsgOffset == -1)
{
if (pPositionCursorForStatus)
{
console.gotoxy(1, console.screen_rows);
console.cleartoeol();
console.gotoxy(this.msgAreaLeft, console.screen_rows);
}
else
console.crlf();
console.print("\x01n\x01h\x01yNo messages found.\x01n");
mswait(ERROR_PAUSE_WAIT_MS);
}
return newMsgOffset;
}
// For the DigDistMsgReader class: Looks for the previous message in the thread of
// a given message (by its header).
//
// Paramters:
// pMsgHdr: A message header object - The previous message in the thread will be
// searched starting from this message

nightfox
committed
// pThreadType: The type of threading to use. Can be THREAD_BY_ID, THREAD_BY_TITLE,
// THREAD_BY_AUTHOR, or THREAD_BY_TO_USER.
// pPositionCursorForStatus: Optional boolean - Whether or not to move the cursor
// to the bottom row before outputting status messages.
// Defaults to false.
//
// Return value: The offset (index) of the previous message thread, or -1 if
// none was found.

nightfox
committed
function DigDistMsgReader_FindThreadPrevOffset(pMsgHdr, pThreadType, pPositionCursorForStatus)
{
if ((pMsgHdr == null) || (typeof(pMsgHdr) != "object"))
return -1;
var newMsgOffset = -1;

nightfox
committed
switch (pThreadType)
{

nightfox
committed
case THREAD_BY_ID:
default:
// The thread_id field was introduced in Synchronet 3.16. So, if
// the Synchronet version is 3.16 or higher and the message header
// has a thread_id field, then look for the previous message with the
// same thread ID. If the Synchronet version is below 3.16 or there
// is no thread ID, then fall back to using the header's thread_next,
// if it exists.
if ((system.version_num >= 31600) && (typeof(pMsgHdr.thread_id) == "number"))
{
// Look for the previous message with the same thread ID.
// Write "Searching.." in case searching takes a while.
console.print("\x01n");
if (pPositionCursorForStatus)
{
console.gotoxy(1, console.screen_rows);
console.cleartoeol();
console.gotoxy(this.msgAreaLeft, console.screen_rows);
}
console.print("\x01h\x01ySearching\x01i...\x01n");
// Look for the previous message in the thread
var nextMsgOffset = -1;
/*
if (pMsgHdr.offset > 0)
{
var prevMsgHdr;
for (var messageIdx = pMsgHdr.offset-1; (messageIdx >= 0) && (nextMsgOffset == -1); --messageIdx)
{
prevMsgHdr = this.GetMsgHdrByIdx(messageIdx);
if (((prevMsgHdr.attr & MSG_DELETE) == 0) && (typeof(prevMsgHdr.thread_id) == "number") && (prevMsgHdr.thread_id == pMsgHdr.thread_id))
nextMsgOffset = prevMsgHdr.offset;
}
}
*/
if (this.GetMsgIdx(pMsgHdr.number) > 0)
{
var prevMsgHdr;
for (var messageIdx = this.GetMsgIdx(pMsgHdr.number)-1; (messageIdx >= 0) && (nextMsgOffset == -1); --messageIdx)
{
prevMsgHdr = this.GetMsgHdrByIdx(messageIdx);
if (((prevMsgHdr.attr & MSG_DELETE) == 0) && (typeof(prevMsgHdr.thread_id) == "number") && (prevMsgHdr.thread_id == pMsgHdr.thread_id))
{
//nextMsgOffset = prevMsgHdr.offset;
nextMsgOffset = this.GetMsgIdx(prevMsgHdr.number);

nightfox
committed
nextMsgOffset = 0;
}
}
}
if (nextMsgOffset > -1)
newMsgOffset = nextMsgOffset;
}
// Fall back to thread_next if the Synchronet version is below 3.16 or there is
// no thread_id field in the header
else if ((typeof(pMsgHdr.thread_back) == "number") && (pMsgHdr.thread_back > 0))

nightfox
committed
{
//newMsgOffset = this.AbsMsgNumToIdx(pMsgHdr.thread_back);
newMsgOffset = this.GetMsgIdx(pMsgHdr.thread_back);
if (newMsgOffset < 0)
newMsgOffset = 0;
}
/*

nightfox
committed
// If thread_back is valid for the message header, then use that.
if ((typeof(pMsgHdr.thread_back) == "number") && (pMsgHdr.thread_back > 0))

nightfox
committed
{
//newMsgOffset = this.AbsMsgNumToIdx(pMsgHdr.thread_back);
newMsgOffset = this.GetMsgIdx(pMsgHdr.thread_back);
}

nightfox
committed
else
{

nightfox
committed
// If thread_id is defined and the index of the first message
// in the thread is before the current message, then search
// backwards for messages with a matching thread_id.

nightfox
committed
//var firstThreadMsgIdx = this.AbsMsgNumToIdx(pMsgHdr.thread_first);
var firstThreadMsgIdx = this.GetMsgIdx(pMsgHdr.thread_first);

nightfox
committed
if ((typeof(pMsgHdr.thread_id) == "number") && (firstThreadMsgIdx < pMsgHdr.offset))
{
// Note (2014-10-11): Digital Man said thread_id was
// introduced in Synchronet version 3.16 and was still
// a work in progress and isn't 100% accurate for
// networked sub-boards.
// Look for the previous message with the same thread ID.
// Note: I'm not sure when thread_id was introduced in
// Synchronet, so I'm not sure of the minimum version where
// this will work.
// Write "Searching.." in case searching takes a while.
console.print("\x01n");

nightfox
committed
if (pPositionCursorForStatus)
{
console.gotoxy(1, console.screen_rows);
console.cleartoeol();
console.gotoxy(this.msgAreaLeft, console.screen_rows);
}
console.print("\x01h\x01ySearching\x01i...\x01n");

nightfox
committed
// Look for the previous message in the thread
var nextMsgOffset = -1;
if (pMsgHdr.offset > 0)
{
for (var messageIdx = pMsgHdr.offset-1; (messageIdx >= 0) && (nextMsgOffset == -1); --messageIdx)
{
var prevMsgHdr = this.GetMsgHdrByIdx(messageIdx);
if (((prevMsgHdr.attr & MSG_DELETE) == 0) && (typeof(prevMsgHdr.thread_id) == "number") && (prevMsgHdr.thread_id == pMsgHdr.thread_id))
nextMsgOffset = prevMsgHdr.offset;
}
}
if (nextMsgOffset > -1)
newMsgOffset = nextMsgOffset;
}
}
*/

nightfox
committed
break;
case THREAD_BY_TITLE:
case THREAD_BY_AUTHOR:
case THREAD_BY_TO_USER:
// Title (subject) searching will look for the subject anywhere in the
// other messages' subjects (not a fully exact subject match), so if
// the message subject is blank, we won't want to do the search.
var doSearch = true;
if ((pThreadType == THREAD_BY_TITLE) && (pMsgHdr.subject.length == 0))
doSearch = false;
if (doSearch)
{

nightfox
committed
12625
12626
12627
12628
12629
12630
12631
12632
12633
12634
12635
12636
12637
12638
12639
12640
12641
12642
12643
12644
12645
12646
12647
12648
12649
12650
12651
12652
12653
12654
12655
12656
12657
12658
12659
12660
12661
12662
var subjUppercase = "";
var fromNameUppercase = "";
var toNameUppercase = "";
// Set up a message header matching function, depending on
// which field of the header we want to match
var msgHdrMatch;
if (pThreadType == THREAD_BY_TITLE)
{
subjUppercase = pMsgHdr.subject.toUpperCase();
// Remove any leading instances of "RE:" from the subject
while (/^RE:/.test(subjUppercase))
subjUppercase = subjUppercase.substr(3);
while (/^RE: /.test(subjUppercase))
subjUppercase = subjUppercase.substr(4);
// Remove any leading & trailing whitespace from the subject
subjUppercase = trimSpaces(subjUppercase, true, true, true);
msgHdrMatch = function(pMsgHdr) {
return (((pMsgHdr.attr & MSG_DELETE) == 0) && (pMsgHdr.subject.toUpperCase().indexOf(subjUppercase, 0) > -1));
};
}
else if (pThreadType == THREAD_BY_AUTHOR)
{
fromNameUppercase = pMsgHdr.from.toUpperCase();
msgHdrMatch = function(pMsgHdr) {
return (((pMsgHdr.attr & MSG_DELETE) == 0) && (pMsgHdr.from.toUpperCase() == fromNameUppercase));
};
}
else if (pThreadType == THREAD_BY_TO_USER)
{
toNameUppercase = pMsgHdr.to.toUpperCase();
msgHdrMatch = function(pMsgHdr) {
return (((pMsgHdr.attr & MSG_DELETE) == 0) && (pMsgHdr.to.toUpperCase() == toNameUppercase));
};
}
// Perform the search
// Write "Searching.." in case searching takes a while.
console.print("\x01n");

nightfox
committed
if (pPositionCursorForStatus)
{
console.gotoxy(1, console.screen_rows);
console.cleartoeol();
console.gotoxy(this.msgAreaLeft, console.screen_rows);
}
console.print("\x01h\x01ySearching\x01i...\x01n");

nightfox
committed
// Look for the next message that contains the given message's subject
var nextMsgOffset = -1;
/*

nightfox
committed
if (pMsgHdr.offset > 0)
{

nightfox
committed
var nextMsgHdr;
for (var messageIdx = pMsgHdr.offset-1; (messageIdx >= 0) && (nextMsgOffset == -1); --messageIdx)
{
nextMsgHdr = this.GetMsgHdrByIdx(messageIdx);
if (msgHdrMatch(nextMsgHdr))
nextMsgOffset = nextMsgHdr.offset;
}
}
*/
if (this.GetMsgIdx(pMsgHdr.number) > 0)
{
var nextMsgHdr;
for (var messageIdx = this.GetMsgIdx(pMsgHdr.number)-1; (messageIdx >= 0) && (nextMsgOffset == -1); --messageIdx)
{
nextMsgHdr = this.GetMsgHdrByIdx(messageIdx);
if (msgHdrMatch(nextMsgHdr))
{
//nextMsgOffset = nextMsgHdr.offset;
nextMsgOffset = this.GetMsgIdx(nextMsgHdr.number);
}
}
}

nightfox
committed
if (nextMsgOffset > -1)
newMsgOffset = nextMsgOffset;
}

nightfox
committed
break;
}
// If no messages were found, then output a message to say so with a momentary pause.
if (newMsgOffset == -1)
{
if (pPositionCursorForStatus)
{
console.gotoxy(1, console.screen_rows);
console.cleartoeol();
console.gotoxy(this.msgAreaLeft, console.screen_rows);
}
else
console.crlf();
console.print("\x01n\x01h\x01yNo messages found.\x01n");
mswait(ERROR_PAUSE_WAIT_MS);
}
return newMsgOffset;
}
// For the DigDistMsgReader class: Calculates the top message index for a page,
// for the traditional-style message list.
//
// Parameters:
// pPageNum: A page number (1-based)
function DigDistMsgReader_CalcTraditionalMsgListTopIdx(pPageNum)
{
if (this.reverseListOrder)
this.tradListTopMsgIdx = this.NumMessages() - (this.tradMsgListNumLines * (pPageNum-1)) - 1;
else
this.tradListTopMsgIdx = (this.tradMsgListNumLines * (pPageNum-1));
}
// For the DigDistMsgReader class: Calculates the top message index for a page,
// for the lightbar message list.
//
// Parameters:
// pPageNum: A page number (1-based)
function DigDistMsgReader_CalcLightbarMsgListTopIdx(pPageNum)
{
if (this.reverseListOrder)
this.lightbarListTopMsgIdx = this.NumMessages() - (this.lightbarMsgListNumLines * (pPageNum-1)) - 1;
else
{
//this.lightbarListTopMsgIdx = (this.lightbarMsgListNumLines * (pPageNum-1));
var pageIdx = pPageNum - 1;
if (pageIdx < 0)
pageIdx = 0;
this.lightbarListTopMsgIdx = this.lightbarMsgListNumLines * pageIdx;
}
}
// For the DigDistMsgReader class: Given a message number (1-based), this calculates
// the screen index veriables (stored in the object) for the message list. This is
// used for the enhanced reader mode when we want the message list to be in the
// correct place for the message being read.
//
// Parameters:
// pMsgNum: The message number (1-based)
function DigDistMsgReader_CalcMsgListScreenIdxVarsFromMsgNum(pMsgNum)
{
// Calculate the message list variables
var numItemsPerPage = this.tradMsgListNumLines;
if (this.msgListUseLightbarListInterface && canDoHighASCIIAndANSI())
numItemsPerPage = this.lightbarMsgListNumLines;
var newPageNum = findPageNumOfItemNum(pMsgNum, numItemsPerPage, this.NumMessages(), this.reverseListOrder);
this.CalcTraditionalMsgListTopIdx(newPageNum);
this.CalcLightbarMsgListTopIdx(newPageNum);
this.lightbarListSelectedMsgIdx = pMsgNum - 1;
if (this.lightbarListCurPos == null)
this.lightbarListCurPos = {};
this.lightbarListCurPos.x = 1;
12774
12775
12776
12777
12778
12779
12780
12781
12782
12783
12784
12785
12786
12787
12788
12789
12790
12791
12792
12793
12794
12795
12796
this.lightbarListCurPos.y = this.lightbarMsgListStartScreenRow + ((pMsgNum-1) - this.lightbarListTopMsgIdx);
}
// For the DigDistMsgReader class: Validates a user's choice in message area.
// Returns a status/error message for the caller to display if there's an
// error. This function outputs intermediate status messages (i.e.,
// "Searching..").
//
// Parameters:
// pGrpIdx: The message group index (i.e., bbs.curgrp)
// pSubIdx: The message sub-board index (i.e., bbs.cursub)
// pCurPos: Optional - An object containing x and y properties representing
// the cursor position. Used for outputting intermediate status
// messages, but not for outputting the error message.
//
// Return value: An object containing the following properties:
// msgAreaGood: A boolean to indicate whether the message area
// can be selected
// errorMsg: If the message area can't be selected, this string
// will contain an eror message. Otherwise, this will
// be an empty string.
function DigDistMsgReader_ValidateMsgAreaChoice(pGrpIdx, pSubIdx, pCurPos)
{
var retObj = {
msgAreaGood: true,
errorMsg: ""
};
12801
12802
12803
12804
12805
12806
12807
12808
12809
12810
12811
12812
12813
12814
12815
12816
12817
12818
12819
12820
12821
12822
12823
12824
12825
12826
12827
12828
12829
12830
12831
// Get the internal code of the sub-board from the given group & sub-board
// indexes
var subCode = msg_area.grp_list[pGrpIdx].sub_list[pSubIdx].code;
// If a search is specified that would populate the search results, then do
// a search in the given sub-board.
if (this.SearchTypePopulatesSearchResults())
{
// See if we can use pCurPos to move the cursor before displaying messages
var useCurPos = (console.term_supports(USER_ANSI) && (typeof(pCurPos) == "object") &&
(typeof(pCurPos.x) == "number") && (typeof(pCurPos.y) == "number"));
// TODO: In case new messages were posted in this sub-board, it might help
// to check the current number of messages vs. the previous number of messages
// and search the new messages if there are more.
// Determine whether or not to search - If there are no search results for
// the given sub-board already, then do a search in the sub-board.
var doSearch = true;
if (this.msgSearchHdrs.hasOwnProperty(subCode) &&
(typeof(this.msgSearchHdrs[subCode]) == "object") &&
(typeof(this.msgSearchHdrs[subCode].indexed) != "undefined"))
{
doSearch = (this.msgSearchHdrs[subCode].indexed.length == 0);
}
if (doSearch)
{
if (useCurPos)
{
console.gotoxy(pCurPos);
console.cleartoeol("\x01n");
console.gotoxy(pCurPos);
}
console.print("\x01n\x01h\x01wSearching\x01i...\x01n");
this.msgSearchHdrs[subCode] = searchMsgbase(subCode, this.searchType, this.searchString, this.readingPersonalEmailFromUser);
// If there are no messages, then set the return object variables to indicate so.
if (this.msgSearchHdrs[subCode].indexed.length == 0)
{
retObj.msgAreaGood = false;
retObj.errorMsg = "No search results found";
12842
12843
12844
12845
12846
12847
12848
12849
12850
12851
12852
12853
12854
12855
12856
12857
12858
12859
12860
12861
12862
12863
}
}
}
else
{
// No search is specified. Just check to see if there are any messages
// to read in the given sub-board.
var msgBase = new MsgBase(subCode);
if (msgBase.open())
{
if (msgBase.total_msgs == 0)
{
retObj.msgAreaGood = false;
retObj.errorMsg = "No messages in that message area";
}
msgBase.close();
}
}
return retObj;
}
// For the DigDistMsgReader class: Validates a message if the sub-board
// requires message validation.
//
// Parameters:
// pSubBoardCode: The internal code of the sub-board
// pMsgNum: The message number
//
// Return value: Boolean - Whether or not validating the message was successful
function DigDistMsgReader_ValidateMsg(pSubBoardCode, pMsgNum)
{
if (!msg_area.sub[pSubBoardCode].is_moderated)
return true;
var validationSuccessful = false;
var msgbase = new MsgBase(this.subBoardCode);
if (msgbase.open())
{
var msgHdr = msgbase.get_msg_header(false, pMsgNum, false);
if (msgHdr != null)
{
if ((msgHdr.attr & MSG_VALIDATED) == 0)
{
msgHdr.attr |= MSG_VALIDATED;
validationSuccessful = msgbase.put_msg_header(false, msgHdr.number, msgHdr);
}
else
validationSuccessful = true;
}
msgbase.close();
}
return validationSuccessful;
}
12898
12899
12900
12901
12902
12903
12904
12905
12906
12907
12908
12909
12910
12911
12912
12913
12914
12915
12916
12917
12918
// For the DigDistMsgReader class: Gets the current sub-board's group name and description.
//
// Return value: An object with the following properties:
// grpName: The group name
// grpDesc: The group description
function DigDistMsgReader_GetGroupNameAndDesc()
{
var retObj = {
grpName: "",
grpDesc: ""
}
var msgbase = new MsgBase(this.subBoardCode);
if (msgbase.open())
{
retObj.grpName = msgbase.cfg.grp_name;
retObj.grpDesc = msgbase.cfg.description;
msgbase.close();
}
return retObj;
}
// For the DigDistMsgReader class: Writes message lines to a file on the BBS
// machine.
//
// Parameters:
// pMsgHdr: The header object for the message
// pFilename: The name of the file to write the message to
//
// Return value: An object containing the following properties:
// succeeded: Boolean - Whether or not the file was successfully written
// errorMsg: String - On failure, will contain the reason it failed
function DigDistMsgReader_SaveMsgToFile(pMsgHdr, pFilename)
{
// Sanity checking
if (typeof(pMsgHdr) !== "object")
return({ succeeded: false, errorMsg: "Header object not given"});
if (typeof(pFilename) != "string")
return({ succeeded: false, errorMsg: "Filename parameter not a string"});
if (pFilename.length == 0)
return({ succeeded: false, errorMsg: "Empty filename given"});
var retObj = {
succeeded: true,
errorMsg: ""
};
// Get the message text and save it
// Note: GetMsgInfoForEnhancedReader() can expand @-codes in the message,
// but for now we're saving the message basically as-is.
//var msgInfo = this.GetMsgInfoForEnhancedReader(pMsgHdr, false, false, false);
var msgbase = new MsgBase(this.subBoardCode);
if (msgbase.open())
{
Eric Oulashin
committed
var msgBody = msgbase.get_msg_body(false, pMsgHdr.number, false, false, true, true);
msgbase.close();
var messageSaveFile = new File(pFilename);
if (messageSaveFile.open("w"))
{
// Write some header information to the file
12958
12959
12960
12961
12962
12963
12964
12965
12966
12967
12968
12969
12970
12971
12972
12973
12974
12975
12976
12977
12978
if (pMsgHdr.hasOwnProperty("from"))
messageSaveFile.writeln("From: " + pMsgHdr.from);
if (pMsgHdr.hasOwnProperty("to"))
messageSaveFile.writeln(" To: " + pMsgHdr.to);
if (pMsgHdr.hasOwnProperty("subject"))
messageSaveFile.writeln("Subj: " + pMsgHdr.subject);
/*
if (pMsgHdr.hasOwnProperty("when_written_time"))
messageSaveFile.writeln(strftime("Date: %Y-%m-%d %H:%M:%S", msgHeader.when_written_time));
*/
if (pMsgHdr.hasOwnProperty("date"))
messageSaveFile.writeln("Date: " + pMsgHdr.date);
if (pMsgHdr.hasOwnProperty("from_net_addr"))
messageSaveFile.writeln("From net address: " + pMsgHdr.from_net_addr);
if (pMsgHdr.hasOwnProperty("to_net_addr"))
messageSaveFile.writeln("To net address: " + pMsgHdr.to_net_addr);
if (pMsgHdr.hasOwnProperty("id"))
messageSaveFile.writeln("ID: " + pMsgHdr.id);
if (pMsgHdr.hasOwnProperty("reply_id"))
messageSaveFile.writeln("Reply ID: " + pMsgHdr.reply_id);
messageSaveFile.writeln("===============================");
// If the message body has ANSI, then use the Graphic object to strip it
// of any cursor movement codes
var msgHasANSICodes = msgBody.indexOf("\x1b[") >= 0;
if (msgHasANSICodes)
{
if (textHasDrawingChars(msgBody))
{
var graphic = new Graphic(this.msgAreaWidth, this.msgAreaHeight);
graphic.auto_extend = true;
graphic.ANSI = ansiterm.expand_ctrl_a(msgBody);
msgBody = syncAttrCodesToANSI(graphic.MSG);
}
else
msgBody = syncAttrCodesToANSI(msgBody);
}
// Write the message body to the file
messageSaveFile.write(msgBody);
messageSaveFile.close();