Newer
Older
var infoLineWrapped = word_wrap(msgHdr[prop], this.msgAreaWidth);
var infoLineWrappedArray = lfexpand(infoLineWrapped).split("\r\n");
var itemValue = "";
for (var lineIdx = 0; lineIdx < infoLineWrappedArray.length; ++lineIdx)
{
if (infoLineWrappedArray[lineIdx].length > 0)
// Set itemValue to the value that should be displayed
if (prop == "when_written_time") //itemValue = system.timestr(msgHdr.when_written_time);
itemValue = system.timestr(msgHdr.when_written_time) + " " + system.zonestr(msgHdr.when_written_zone);
else if (prop == "when_imported_time") //itemValue = system.timestr(msgHdr.when_imported_time);
itemValue = system.timestr(msgHdr.when_imported_time) + " " + system.zonestr(msgHdr.when_imported_zone);
else if ((prop == "when_imported_zone") || (prop == "when_written_zone"))
itemValue = system.zonestr(msgHdr[prop]);
else if (prop == "attr")
itemValue = makeMainMsgAttrStr(msgHdr[prop], "None");
else if (prop == "auxattr")
itemValue = makeAuxMsgAttrStr(msgHdr[prop], "None");
else if (prop == "netattr")
itemValue = makeNetMsgAttrStr(msgHdr[prop], "None");
else
itemValue = infoLineWrappedArray[lineIdx];
// Add the value color to the value text
itemValue = "\1n" + this.colors.hdrLineValueColor + itemValue + "\1n";
var hdrItem = propLabel + " " + itemValue;
if (strip_ctrl(hdrItem).length < this.msgAreaWidth)
12028
12029
12030
12031
12032
12033
12034
12035
12036
12037
12038
12039
12040
12041
12042
12043
12044
12045
12046
12047
12048
12049
12050
msgHdrInfoLines.push(hdrItem);
else
{
// If this isn't the first header property, then add an empty
// line to the info lines array for spacing
if (propCounter > 1)
msgHdrInfoLines.push("");
msgHdrInfoLines.push(propLabel);
// In case the item value is too long to fit into the
// message reading area, split it and add all the split lines.
var itemValueWrapped = word_wrap(itemValue, this.msgAreaWidth);
var itemValueWrappedArray = lfexpand(itemValueWrapped).split("\r\n");
for (var lineIdx = 0; lineIdx < itemValueWrappedArray.length; ++lineIdx)
{
if (itemValueWrappedArray[lineIdx].length > 0)
msgHdrInfoLines.push(itemValueWrappedArray[lineIdx]);
}
// If this isn't the first header property, then add an empty
// line to the info lines array for spacing
if (propCounter > 1)
msgHdrInfoLines.push("");
}
}

nightfox
committed
++propCounter;
}
// If some info lines were added, then insert a header line & blank line to
// the beginning of the array, and remove the last empty line from the array.
if (msgHdrInfoLines.length > 0)
{
if (kludgeOnly)
{
msgHdrInfoLines.splice(0, 0, "\1n\1c\1hMessage Information/Kludge Lines\1n");
msgHdrInfoLines.splice(1, 0, "\1n\1g\1h--------------------------------\1n");
}
else
{
msgHdrInfoLines.splice(0, 0, "\1n\1c\1hMessage Headers\1n");
msgHdrInfoLines.splice(1, 0, "\1n\1g\1h---------------\1n");
if (msgHdrInfoLines[msgHdrInfoLines.length-1].length == 0)
msgHdrInfoLines.pop();
}
// For the DigDistMsgReader class: Gets & prepares message information for
// the enhanced reader.
//
// Parameters:
// pMsgHdr: The message header
// pWordWrap: Boolean - Whether or not to word-wrap the message to fit into the
// display area. This is optional and defaults to true. This should
// be true for normal use; the only time this should be false is when
// saving the message to a file.
// pDetermineAttachments: Boolean - Whether or not to parse the message text to
// get attachments from it. This is optional and defaults
// to true. If false, then the message text will be left
// intact with any base64-encoded attachments that may be
// in the message text (for multi-part MIME messages).
// pGetB64Data: Boolean - Whether or not to get the Base64-encoded data for
// base64-encoded attachments (i.e., in multi-part MIME emails).
// This is optional and defaults to true. This is only used when
// pDetermineAttachments is true.
// pMsgBody: Optional - A string containing the message body. If this is not included
// or is not a string, then this method will retrieve the message body.
// pMsgHasANSICodes: Optional boolean - If the caller already knows whether the
// message text has ANSI codes, the caller can pass this parameter.
//
// Return value: An object with the following properties:
// msgText: The unaltered message text
// messageLines: An array containing the message lines, wrapped to
// the message area width
// topMsgLineIdxForLastPage: The top message line index for the last page
// msgFractionShown: The fraction of the message shown
// numSolidScrollBlocks: The number of solid scrollbar blocks
// numNonSolidScrollBlocks: The number of non-solid scrollbar blocks
// solidBlockStartRow: The starting row on the screen for the scrollbar blocks
// attachments: An array of the attached filenames (as strings)
// displayFrame: A Frame object for displaying the message with
// a scrollable interface. Used when the message
// contains ANSI, for instance. If this object is
// null, then the reader should use its own scrolling
// interface. Also, this will only be available if
// the BBS machine has frame.js in sbbs/exec/load.
// displayFrameScrollbar: A ScrollBar object to work with displayFrame.
// If scrollbar.js is not available on the BBS machine,
// this will be null.
// errorMsg: An error message, if something bad happened
function DigDistMsgReader_GetMsgInfoForEnhancedReader(pMsgHdr, pWordWrap, pDetermineAttachments,
pGetB64Data, pMsgBody, pMsgHasANSICodes)
{
var retObj = {
msgText: "",
messageLines: [],
topMsgLineIdxForLastPage: 0,
msgFractionShown: 0.0,
numSolidScrollBlocks: 0,
numNonSolidScrollBlocks: 0,
solidBlockStartRow: 0,
attachments: [],
displayFrame: null,
displayFrameScrollbar: null,
errorMsg: ""
};
var determineAttachments = true;
if (typeof(pDetermineAttachments) == "boolean")
determineAttachments = pDetermineAttachments;
var getB64Data = true;
if (typeof(pGetB64Data) == "boolean")
getB64Data = pGetB64Data;
12145
12146
12147
12148
12149
12150
12151
12152
12153
12154
12155
12156
12157
12158
12159
12160
12161
var msgBody = "";
if (typeof(pMsgBody) == "string")
msgBody = pMsgBody;
else
{
var msgbase = new MsgBase(this.subBoardCode);
if (msgbase.open())
{
msgBody = msgbase.get_msg_body(false, pMsgHdr.number);
msgbase.close();
}
else
{
retObj.errorMsg = "Unable to open the sub-board";
return retObj;
}
}
if (determineAttachments)
{
var msgInfo = determineMsgAttachments(pMsgHdr, msgBody, getB64Data);
retObj.msgText = msgInfo.msgText;
retObj.attachments = msgInfo.attachments;
}
else
{
retObj.attachments = [];
}
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, pMsgHdr); // 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.
if ((system.settings & SYS_RENEGADE) == SYS_RENEGADE)
msgTextAltered = renegadeAttrsToSyncAttrs(msgTextAltered);
if ((system.settings & SYS_WWIV) == SYS_WWIV)
msgTextAltered = WWIVAttrsToSyncAttrs(msgTextAltered);
if ((system.settings & SYS_CELERITY) == SYS_CELERITY)
msgTextAltered = celerityAttrsToSyncAttrs(msgTextAltered);
if ((system.settings & SYS_PCBOARD) == SYS_PCBOARD)
msgTextAltered = PCBoardAttrsToSyncAttrs(msgTextAltered);
if ((system.settings & SYS_WILDCAT) == SYS_WILDCAT)
msgTextAltered = wildcatAttrsToSyncAttrs(msgTextAltered);
// If the message contains ANSI codes, then if frame.js is available and
// the user's terminal support ANSI, set up a Frame object for reading the
// message with a scrollable interface.
var msgHasANSICodes = (typeof(pMsgHasANSICodes) == "boolean" ? pMsgHasANSICodes : textHasANSICodes(retObj.msgText));

nightfox
committed
// If the message has ANSI codes, then check to see if the amount of ANSI is very low.
// If so, then convert the ANSI color codes to Synchronet codes and eliminate unwanted
// ANSI (such as cursor movement codes). It seems that some messages have ANSI inserted
// into them that shouldn't be there (i.e., the author didn't intend to post an ANSI
// message), which is the reason for this check. If the message contains such rogue
// ANSI codes, they could mess up the display of the message.
if (msgHasANSICodes)
{
// ANSI content checking
var lastANSIIdx = idxOfLastANSICode(msgTextAltered, gANSIRegexes);
var numCharsAfterFirstANSI = msgTextAltered.length - idxOfFirstANSICode(msgTextAltered, gANSIRegexes) - 1;

nightfox
committed
// Count the number of ANSI codes in the message and find the percentage of
// ANSI in the message.
var ANSICodeCount = countANSICodes(msgTextAltered, gANSIRegexes);
var percentANSICodes = (ANSICodeCount / msgTextAltered.length) * 100;
// It seems that some messages contain a couple extra lines at the beginning with
// a "By: <name> to <name>" and a date, and some of those messages contain ANSI
// codes in those lines, which will mess up the display of the message using the
// scrolling interface. Also, some messages might have ANSI codes in the signature.
// If the last index of ANSI codes is <= 160 or there are <= 100 characters after
// the first ANSI code (possibly in the signature) or if less than 7% of the message
// is ANSI codes, then consider those ANSI codes unwanted and convert them to
// Synchronet codes and remove unwanted ANSI.
if ((percentANSICodes < 10) || (lastANSIIdx <= 160) || (numCharsAfterFirstANSI <= 100))
{
msgTextAltered = cvtANSIToSyncAndRemoveUnwantedANSI(msgTextAltered);

nightfox
committed
//msgTextAltered = removeANSIFromStr(msgTextAltered, gANSIRegexes);
12225
12226
12227
12228
12229
12230
12231
12232
12233
12234
12235
12236
12237
12238
12239
12240
12241
12242
12243
12244
12245
12246
12247
12248
12249
12250
12251
12252
12253
12254
12255
12256
12257
msgHasANSICodes = false;
}
}
// 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 first240Chars = msgTextWithoutAttrs.substr(0, 240);
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);
}
// If the message (still) has ANSI codes, then it is probably an ANSI message.
// Set up a Frame object to display the message, since the Frame object handles
// ANSI well with scrolling.
if (msgHasANSICodes)
{
if (gFrameJSAvailable && console.term_supports(USER_ANSI))
{
// Write the message to a file in a temporary directory,
// have the frame object read it, then delete the temporary
// directory.
var readerTmpOutputDir = backslash(system.node_dir + "DDMsgReaderANSIMsgTemp");
var ANSITempDirExists = file_exists(readerTmpOutputDir);
if (!ANSITempDirExists)
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
12294
12295
12296
12297
ANSITempDirExists = mkdir(readerTmpOutputDir);
if (ANSITempDirExists)
{
var tmpANSIFileName = backslash(readerTmpOutputDir) + "tmpMsg.ans";
var tmpANSIFile = new File(tmpANSIFileName);
if (tmpANSIFile.open("w"))
{
var tmpANSIFileWritten = tmpANSIFile.write(msgTextAltered);
tmpANSIFile.close();
// If the file was successfully written, then create the
// Frame object and have it read the file.
if (tmpANSIFileWritten)
{
// Create the Frame object and
// TODO: Should this use 79 or 80 columns?
retObj.displayFrame = new Frame(1, // x: Horizontal coordinate of top left
this.enhMsgHeaderLines.length+1, // y: Vertical coordinate of top left
80, // Width
// Height: Allow for the message header
// and enhanced reader help line
console.screen_rows-this.enhMsgHeaderLines.length-1,
BG_BLACK);
retObj.displayFrame.v_scroll = true;
retObj.displayFrame.h_scroll = false;
retObj.displayFrame.scrollbars = true;
// Load the message file into the Frame object
retObj.displayFrame.load(tmpANSIFileName);
// If scrollbar.js is available, then set up a vertical
// scrollbar for the Frame object
if (gScrollbarJSAvailable)

nightfox
committed
retObj.displayFrameScrollbar = new ScrollBar(retObj.displayFrame, {bg: BG_BLACK, fg: LIGHTGRAY, orientation: "vertical", autohide: false});
}
}
// Cleanup: Remove the temporary directory
deltree(readerTmpOutputDir);
}
}
else
{
// frame.js is not available. Just convert the ANSI to
// Synchronet attributes. It might not look the best, but
// at least we can convert some of the ANSI codes.
msgTextAltered = ANSIAttrsToSyncAttrs(msgTextAltered);
}
}
12313
12314
12315
12316
12317
12318
12319
12320
12321
12322
12323
12324
12325
12326
12327
12328
12329
12330
12331
12332
12333
12334
12335
12336
12337
12338
12339
12340
12341
12342
12343
12344
12345
12346
12347
12348
12349
12350
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);
}
12351
12352
12353
12354
12355
12356
12357
12358
12359
12360
12361
12362
12363
12364
12365
12366
12367
12368
12369
12370
12371
12372
12373
12374
12375
12376
12377
12378
12379
12380
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
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: The index of the last read message in the current message area
function DigDistMsgReader_GetLastReadMsgIdx(pMailStartFromFirst)
{
var msgIndex = -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)
msgIndex = idx;
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)
{
msgIndex = idx;
break;
}
}
}
// Sanity checking for msgIndex (note: this function should return -1 if
// there is no last read message).
if (msgIndex >= this.msgSearchHdrs[this.subBoardCode].indexed.length)
msgIndex = this.msgSearchHdrs[this.subBoardCode].indexed.length - 1;
}
}
else
{

nightfox
committed
//msgIndex = this.AbsMsgNumToIdx(msg_area.sub[this.subBoardCode].last_read);
msgIndex = this.GetMsgIdx(msg_area.sub[this.subBoardCode].last_read);
/*
this.hdrsForCurrentSubBoard = new Array();
// hdrsForCurrentSubBoardByMsgNum is an object that maps absolute message numbers
// to their index to hdrsForCurrentSubBoard
this.hdrsForCurrentSubBoardByMsgNum = new Object();
*/
// Sanity checking for msgIndex (note: this function should return -1 if
// there is no last read message).
var msgbase = new MsgBase(this.subBoardCode);
if (msgbase.open())
{
// If msgIndex 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 (msgIndex == -1)
{
var msgIdxAccordingToMsgbase = absMsgNumToIdx(msgbase, msg_area.sub[this.subBoardCode].last_read);
if ((this.hdrsForCurrentSubBoard.length > 0) && (msgIdxAccordingToMsgbase >= this.hdrsForCurrentSubBoard.length))
msgIndex = this.hdrsForCurrentSubBoard.length - 1;
}
//if (msgIndex >= msgbase.total_msgs)
// msgIndex = msgbase.total_msgs - 1;
// TODO: Is this code right? Modified 3/24/2015 to replace
// the above 2 commented lines.
if ((msgIndex < 0) || (msgIndex >= msgbase.total_msgs))
12436
12437
12438
12439
12440
12441
12442
12443
12444
12445
12446
12447
12448
12449
12450
12451
12452
12453
12454
12455
12456
12457
12458
12459
12460
12461
12462
12463
12464
12465
12466
12467
12468
{
// 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 msgIndex;
}
// 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 (msg_area.sub[this.subBoardCode].scan_ptr != 4294967295) // Crazy value the first time a user reads messages

nightfox
committed
//msgIdx = this.AbsMsgNumToIdx(msg_area.sub[this.subBoardCode].scan_ptr);
if (msg_area.sub[this.subBoardCode].scan_ptr != 4294967295) // Crazy value the first time a user reads messages
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))
{
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();
12499
12500
12501
12502
12503
12504
12505
12506
12507
12508
12509
12510
12511
12512
12513
12514
12515
12516
12517
12518
12519
12520
12521
12522
12523
12524
12525
12526
12527
12528
12529
12530
12531
12532
12533
12534
12535
12536
12537
12538
12539
12540
12541
12542
12543
}
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:
12563
12564
12565
12566
12567
12568
12569
12570
12571
12572
12573
12574
12575
12576
12577
12578
12579
12580
12581
12582
12583
// 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("\1n");
if (pPositionCursorForStatus)
{
console.gotoxy(1, console.screen_rows);
console.cleartoeol();
console.gotoxy(this.msgAreaLeft, console.screen_rows);
}
console.print("\1h\1ySearching\1i...\1n");
// 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
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
12663
12664
12665
12666
12667
12668
12669
12670
12671
12672
12673
12674
12675
12676
12677
12678
12679
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("\1n");
if (pPositionCursorForStatus)
{
console.gotoxy(1, console.screen_rows);
console.cleartoeol();
console.gotoxy(this.msgAreaLeft, console.screen_rows);
}
console.print("\1h\1ySearching\1i...\1n");
// 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("\1n\1h\1yNo messages found.\1n");
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:
12754
12755
12756
12757
12758
12759
12760
12761
12762
12763
12764
12765
12766
12767
12768
12769
12770
12771
12772
12773
// 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("\1n");
if (pPositionCursorForStatus)
{
console.gotoxy(1, console.screen_rows);
console.cleartoeol();
console.gotoxy(this.msgAreaLeft, console.screen_rows);
}
console.print("\1h\1ySearching\1i...\1n");
// 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
12827
12828
12829
12830
12831
12832
12833
12834
12835
12836
12837
12838
12839
12840
12841
12842
12843
12844
12845
12846
12847
12848
12849
12850
12851
12852
12853
12854
12855
12856
12857
12858
12859
12860
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("\1n");
if (pPositionCursorForStatus)
{
console.gotoxy(1, console.screen_rows);
console.cleartoeol();
console.gotoxy(this.msgAreaLeft, console.screen_rows);
}
console.print("\1h\1ySearching\1i...\1n");
// 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
12875
12876
12877
12878
12879
12880
12881
12882
12883
12884
12885
12886
12887
12888
12889
12890
12891
12892
12893
12894
12895
12896
12897
12898
12899
12900
12901
12902
12903
12904
12905
12906
12907
12908
12909
12910
12911
12912
12913
12914
12915
12916
12917
12918
12919
12920
12921
12922
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("\1n");
if (pPositionCursorForStatus)
{
console.gotoxy(1, console.screen_rows);
console.cleartoeol();
console.gotoxy(this.msgAreaLeft, console.screen_rows);
}
console.print("\1h\1ySearching\1i...\1n");
// 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("\1n\1h\1yNo messages found.\1n");
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;