Newer
Older
11001
11002
11003
11004
11005
11006
11007
11008
11009
11010
11011
11012
11013
11014
11015
11016
11017
11018
11019
11020
11021
11022
11023
11024
11025
11026
11027
11028
11029
11030
11031
11032
11033
11034
11035
returnValue = 1;
return returnValue;
});
}
else if (pSortType == "dateDesc")
{
subBoardArray.sort(function(pA, pB)
{
// Return -1, 0, or 1, depending on whether pA's date comes
// after, is equal to, or comes before pB's date.
var returnValue = 0;
if (pA.newestPostDate > pB.newestPostDate)
returnValue = -1;
else if (pA.newestPostDate < pB.newestPostDate)
returnValue = 1;
return returnValue;
});
}
else if (pSortType == "description")
{
// Binary safe string comparison
//
// version: 909.322
// discuss at: http://phpjs.org/functions/strcmp // + original by: Waldo Malqui Silva
// + input by: Steve Hilder
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + revised by: gorthaur
// * example 1: strcmp( 'waldo', 'owald' ); // * returns 1: 1
// * example 2: strcmp( 'owald', 'waldo' );
// * returns 2: -1
subBoardArray.sort(function(pA, pB)
{
return ((pA.description == pB.description) ? 0 : ((pA.description > pB.description) ? 1 : -1));
});
}
11037
11038
11039
11040
11041
11042
11043
11044
11045
11046
11047
11048
11049
11050
11051
11052
11053
11054
11055
11056
11057
11058
11059
11060
11061
// Display the sub-board list.
for (var i = 0; i < subBoardArray.length; ++i)
{
console.crlf();
console.print((subBoardArray[i].subBoardNum == highlightIndex) ? "\1n" +
this.colors.areaChooserMsgAreaMarkColor + "*" : " ");
printf(this.subBoardListPrintfInfo[grpIndex].printfStr, +(subBoardArray[i].subBoardNum+1),
subBoardArray[i].description.substr(0, this.subBoardNameLen),
subBoardArray[i].numPosts, strftime("%Y-%m-%d", subBoardArray[i].newestPostDate),
strftime("%H:%M:%S", subBoardArray[i].newestPostDate));
}
}
// If no sort type is specified, then output the sub-board information in
// order of sub-board number.
else
{
for (var arrSubBoardNum in msg_area.grp_list[grpIndex].sub_list)
{
// Open the current sub-board with the msgBase object.
msgBase = new MsgBase(msg_area.grp_list[grpIndex].sub_list[arrSubBoardNum].code);
if (msgBase.open())
{
// Get the date & time when the last message was imported.
if (msgBase.total_msgs > 0)
{
msgHeader = msgBase.get_msg_header(true, msgBase.total_msgs-1, false);
// Construct the date & time strings of the latest post
if (this.msgAreaList_lastImportedMsg_showImportTime)
{
newestDate.date = strftime("%Y-%m-%d", msgHeader.when_imported_time);
newestDate.time = strftime("%H:%M:%S", msgHeader.when_imported_time);
}
else
{
//newestDate.date = strftime("%Y-%m-%d", msgHeader.when_written_time);
//newestDate.time = strftime("%H:%M:%S", msgHeader.when_written_time);
var msgWrittenLocalTime = msgWrittenTimeToLocalBBSTime(msgHeader);
if (msgWrittenLocalTime != -1)
{
newestDate.date = strftime("%Y-%m-%d", msgWrittenLocalTime);
newestDate.time = strftime("%H:%M:%S", msgWrittenLocalTime);
}
else
{
newestDate.date = strftime("%Y-%m-%d", msgHeader.when_written_time);
newestDate.time = strftime("%H:%M:%S", msgHeader.when_written_time);
}
}
}
else
newestDate.date = newestDate.time = "";
// Print the sub-board information
subBoardNum = +(arrSubBoardNum);
console.crlf();
console.print((subBoardNum == highlightIndex) ? "\1n" +
this.colors.areaChooserMsgAreaMarkColor + "*" : " ");
printf(this.subBoardListPrintfInfo[grpIndex].printfStr, +(subBoardNum+1),
msg_area.grp_list[grpIndex].sub_list[arrSubBoardNum].description.substr(0, this.subBoardListPrintfInfo[grpIndex].nameLen),
msgBase.total_msgs, newestDate.date, newestDate.time);
msgBase.close();
}
// Free some memory?
delete msgBase;
}
}
11105
11106
11107
11108
11109
11110
11111
11112
11113
11114
11115
11116
11117
11118
11119
11120
11121
11122
11123
11124
}
//////////////////////////////////////////////
// Message group list stuff (lightbar mode) //
//////////////////////////////////////////////
// Displays a screenful of message groups, for the lightbar interface.
//
// Parameters:
// pStartIndex: The message group index to start at (0-based)
// pStartScreenRow: The row on the screen to start at (1-based)
// pEndScreenRow: The row on the screen to end at (1-based)
// pClearScreenFirst: Boolean - Whether or not to clear the screen first
// pBlankToEndRow: Boolean - Whether or not to write blank lines to the end
// screen row if there aren't enough message groups to fill
// the screen.
function DigDistMsgReader_listScreenfulOfMsgGrps(pStartIndex, pStartScreenRow,
pEndScreenRow, pClearScreenFirst,
pBlankToEndRow)
{
// Check the parameters; If they're bad, then just return.
if ((typeof(pStartIndex) != "number") ||
(typeof(pStartScreenRow) != "number") ||
(typeof(pEndScreenRow) != "number"))
{
return;
}
if ((pStartIndex < 0) || (pStartIndex >= msg_area.grp_list.length))
return;
if ((pStartScreenRow < 1) || (pStartScreenRow > console.screen_rows))
return;
if ((pEndScreenRow < 1) || (pEndScreenRow > console.screen_rows))
return;
// If pStartScreenRow is greather than pEndScreenRow, then swap them.
if (pStartScreenRow > pEndScreenRow)
{
var temp = pStartScreenRow;
pStartScreenRow = pEndScreenRow;
pEndScreenRow = temp;
}
// Calculate the ending index to use for the message groups array.
var endIndex = pStartIndex + (pEndScreenRow-pStartScreenRow);
if (endIndex >= msg_area.grp_list.length)
endIndex = msg_area.grp_list.length - 1;
var onePastEndIndex = endIndex + 1;
// Clear the screen, go to the specified screen row, and display the message
// group information.
if (pClearScreenFirst)
console.clear("\1n");
console.gotoxy(1, pStartScreenRow);
var grpIndex = pStartIndex;
for (; grpIndex < onePastEndIndex; ++grpIndex)
{
this.WriteMsgGroupLine(grpIndex, false);
if (grpIndex < endIndex)
console.crlf();
}
// If pBlankToEndRow is true and we're not at the end row yet, then
// write blank lines to the end row.
if (pBlankToEndRow)
{
var screenRow = pStartScreenRow + (endIndex - pStartIndex) + 1;
if (screenRow <= pEndScreenRow)
{
for (; screenRow <= pEndScreenRow; ++screenRow)
{
console.gotoxy(1, screenRow);
console.clearline("\1n");
}
}
}
}
// For the DigDistMsgReader class - Writes a message group information line.
//
// Parameters:
// pGrpIndex: The index of the message group to write (assumed to be valid)
// pHighlight: Boolean - Whether or not to write the line highlighted.
function DigDistMsgReader_writeMsgGroupLine(pGrpIndex, pHighlight)
{
// TODO: If pHighlight is true, that causes the screen to be cleared
// and the line is written on the first row of the console.
console.print("\1n");
// Write the highlight background color if pHighlight is true.
if (pHighlight)
console.print(this.colors.areaChooserMsgAreaBkgHighlightColor);
// Write the message group information line
console.print(((typeof(bbs.curgrp) == "number") && (pGrpIndex == msg_area.sub[this.subBoardCode].grp_index)) ? this.colors.areaChooserMsgAreaMarkColor + "*" : " ");
printf((pHighlight ? this.msgGrpListHilightPrintfStr : this.msgGrpListPrintfStr),
+(pGrpIndex+1),
msg_area.grp_list[pGrpIndex].description.substr(0, this.msgGrpDescLen),
msg_area.grp_list[pGrpIndex].sub_list.length);
console.cleartoeol("\1n");
11203
11204
11205
11206
11207
11208
11209
11210
11211
11212
11213
11214
11215
11216
11217
11218
11219
11220
11221
11222
}
//////////////////////////////////////////////////
// Message sub-board list stuff (lightbar mode) //
//////////////////////////////////////////////////
// Updates the page number text in the group list header line on the screen.
//
// Parameters:
// pPageNum: The page number
// pNumPages: The total number of pages
// pGroup: Boolean - Whether or not this is for the group header. If so,
// then this will go to the right location for the group page text
// and use this.colors.areaChooserMsgAreaHeaderColor for the text.
// Otherwise, this will go to the right place for the sub-board page
// text and use the sub-board header color.
// pRestoreCurPos: Optional - Boolean - If true, then move the cursor back
// to the position where it was before this function was called
function DigDistMsgReader_updateMsgAreaPageNumInHeader(pPageNum, pNumPages, pGroup, pRestoreCurPos)
{
var originalCurPos = null;
if (pRestoreCurPos)
originalCurPos = console.getxy();
if (pGroup)
{
console.print("\1n" + this.colors.areaChooserMsgAreaHeaderColor + pPageNum + " of " +
pNumPages + ") ");
}
else
{
console.print("\1n" + this.colors.areaChooserSubBoardHeaderColor + pPageNum + " of " +
pNumPages + ") ");
}
if (pRestoreCurPos)
console.gotoxy(originalCurPos);
}
// Displays a screenful of message sub-boards, for the lightbar interface.
//
// Parameters:
// pGrpIndex: The index of the message group (0-based)
// pStartSubIndex: The message sub-board index to start at (0-based)
// pStartScreenRow: The row on the screen to start at (1-based)
// pEndScreenRow: The row on the screen to end at (1-based)
// pClearScreenFirst: Boolean - Whether or not to clear the screen first
// pBlankToEndRow: Boolean - Whether or not to write blank lines to the end
// screen row if there aren't enough message groups to fill
// the screen.
function DigDistMsgReader_ListScreenfulOfSubBrds(pGrpIndex, pStartSubIndex,
pStartScreenRow, pEndScreenRow,
pClearScreenFirst, pBlankToEndRow)
{
11259
11260
11261
11262
11263
11264
11265
11266
11267
11268
11269
11270
11271
11272
11273
11274
11275
11276
11277
11278
11279
11280
11281
11282
11283
11284
// Check the parameters; If they're bad, then just return.
if ((typeof(pGrpIndex) != "number") ||
(typeof(pStartSubIndex) != "number") ||
(typeof(pStartScreenRow) != "number") ||
(typeof(pEndScreenRow) != "number"))
{
return;
}
if ((pGrpIndex < 0) || (pGrpIndex >= msg_area.grp_list.length))
return;
if ((pStartSubIndex < 0) ||
(pStartSubIndex >= msg_area.grp_list[pGrpIndex].sub_list.length))
{
return;
}
if ((pStartScreenRow < 1) || (pStartScreenRow > console.screen_rows))
return;
if ((pEndScreenRow < 1) || (pEndScreenRow > console.screen_rows))
return;
// If pStartScreenRow is greather than pEndScreenRow, then swap them.
if (pStartScreenRow > pEndScreenRow)
{
var temp = pStartScreenRow;
pStartScreenRow = pEndScreenRow;
pEndScreenRow = temp;
}
// Calculate the ending index to use for the sub-board array.
var endIndex = pStartSubIndex + (pEndScreenRow-pStartScreenRow);
if (endIndex >= msg_area.grp_list[pGrpIndex].sub_list.length)
endIndex = msg_area.grp_list[pGrpIndex].sub_list.length - 1;
var onePastEndIndex = endIndex + 1;
// Clear the screen and go to the specified screen row.
if (pClearScreenFirst)
console.clear("\1n");
console.gotoxy(1, pStartScreenRow);
// Start listing the sub-boards.
var subIndex = pStartSubIndex;
for (; subIndex < onePastEndIndex; ++subIndex)
{
this.WriteMsgSubBoardLine(pGrpIndex, subIndex, false);
if (subIndex < endIndex)
console.crlf();
}
// If pBlankToEndRow is true and we're not at the end row yet, then
// write blank lines to the end row.
if (pBlankToEndRow)
{
var screenRow = pStartScreenRow + (endIndex - pStartSubIndex) + 1;
if (screenRow <= pEndScreenRow)
{
for (; screenRow <= pEndScreenRow; ++screenRow)
{
console.gotoxy(1, screenRow);
console.clearline("\1n");
}
}
}
}
// For the DigDistMsgReader class: Writes a message sub-board information line for
// the message area chooser functionality.
//
// Parameters:
// pGrpIndex: The index of the message group (assumed to be valid)
// pSubIndex: The index of the sub-board within the message group to write (assumed to be valid)
// pHighlight: Boolean - Whether or not to write the line highlighted.
function DigDistMsgReader_WriteMsgSubBrdLine(pGrpIndex, pSubIndex, pHighlight)
{
11332
11333
11334
11335
11336
11337
11338
11339
11340
11341
11342
11343
11344
11345
11346
11347
11348
11349
11350
11351
console.print("\1n");
// Write the highlight background color if pHighlight is true.
if (pHighlight)
console.print(this.colors.areaChooserMsgAreaBkgHighlightColor);
// Determine if pGrpIndex and pSubIndex specify the user's
// currently-selected group and sub-board.
var currentSub = false;
if ((typeof(bbs.curgrp) == "number") && (typeof(bbs.cursub) == "number"))
currentSub = ((pGrpIndex == msg_area.sub[this.subBoardCode].grp_index) && (pSubIndex == msg_area.sub[this.subBoardCode].index));
// Open the current sub-board with the msgBase object (so that we can get
// the date & time of the last imporeted message).
var msgBase = new MsgBase(msg_area.grp_list[pGrpIndex].sub_list[pSubIndex].code);
if (msgBase.open())
{
var newestDate = new Object(); // For storing the date of the newest post
// Get the date & time when the last message was imported.
if (msgBase.total_msgs > 0)
{
msgHeader = msgBase.get_msg_header(true, msgBase.total_msgs-1, false);
// Construct the date & time strings of the latest post
if (this.msgAreaList_lastImportedMsg_showImportTime)
{
newestDate.date = strftime("%Y-%m-%d", msgHeader.when_imported_time);
newestDate.time = strftime("%H:%M:%S", msgHeader.when_imported_time);
}
else
{
//newestDate.date = strftime("%Y-%m-%d", msgHeader.when_written_time);
//newestDate.time = strftime("%H:%M:%S", msgHeader.when_written_time);
var msgWrittenLocalTime = msgWrittenTimeToLocalBBSTime(msgHeader);
if (msgWrittenLocalTime != -1)
{
newestDate.date = strftime("%Y-%m-%d", msgWrittenLocalTime);
newestDate.time = strftime("%H:%M:%S", msgWrittenLocalTime);
}
else
{
newestDate.date = strftime("%Y-%m-%d", msgHeader.when_written_time);
newestDate.time = strftime("%H:%M:%S", msgHeader.when_written_time);
}
}
}
else
newestDate.date = newestDate.time = "";
// Print the sub-board information line.
console.print(currentSub ? this.colors.areaChooserMsgAreaMarkColor + "*" : " ");
printf((pHighlight ? this.subBoardListPrintfInfo[pGrpIndex].highlightPrintfStr : this.subBoardListPrintfInfo[pGrpIndex].printfStr),
+(pSubIndex+1),
msg_area.grp_list[pGrpIndex].sub_list[pSubIndex].description.substr(0, this.subBoardListPrintfInfo[pGrpIndex].nameLen),
msgBase.total_msgs, newestDate.date, newestDate.time);
msgBase.close();
delete msgBase;
}
11389
11390
11391
11392
11393
11394
11395
11396
11397
11398
11399
11400
11401
11402
11403
11404
11405
11406
11407
11408
11409
11410
11411
11412
11413
11414
11415
11416
11417
11418
11419
11420
11421
11422
11423
11424
11425
11426
11427
11428
11429
11430
11431
11432
11433
11434
11435
11436
11437
11438
11439
11440
11441
11442
11443
11444
11445
11446
11447
11448
11449
11450
11451
11452
11453
11454
11455
11456
11457
11458
11459
11460
11461
11462
11463
11464
11465
11466
11467
11468
11469
11470
11471
11472
11473
11474
11475
11476
11477
11478
11479
11480
11481
11482
11483
11484
11485
11486
11487
11488
11489
11490
11491
11492
11493
11494
11495
11496
11497
11498
11499
11500
11501
11502
11503
11504
11505
}
///////////////////////////////////////////////
// Other functions for the msg. area chooser //
///////////////////////////////////////////////
// For the DigDistMsgReader class: Shows the help screen
//
// Parameters:
// pLightbar: Boolean - Whether or not to show lightbar help. If
// false, then this function will show regular help.
// pClearScreen: Boolean - Whether or not to clear the screen first
function DigDistMsgReader_showChooseMsgAreaHelpScreen(pLightbar, pClearScreen)
{
if (pClearScreen && console.term_supports(USER_ANSI))
console.clear("\1n");
else
console.print("\1n");
DisplayProgramInfo();
console.crlf();
console.print("\1n\1c\1hMessage area (sub-board) chooser");
console.crlf();
console.print("\1kÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\1n");
console.crlf();
console.print("\1cFirst, a listing of message groups is displayed. One can be chosen by typing");
console.crlf();
console.print("its number. Then, a listing of sub-boards within that message group will be");
console.crlf();
console.print("shown, and one can be chosen by typing its number.");
console.crlf();
if (pLightbar)
{
console.crlf();
console.print("\1n\1cThe lightbar interface also allows up & down navigation through the lists:");
console.crlf();
console.print("\1k\1hÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ");
console.crlf();
console.print("\1n\1c\1hUp arrow\1n\1c: Move the cursor up one line");
console.crlf();
console.print("\1hDown arrow\1n\1c: Move the cursor down one line");
console.crlf();
console.print("\1hENTER\1n\1c: Select the current group/sub-board");
console.crlf();
console.print("\1hHOME\1n\1c: Go to the first item on the screen");
console.crlf();
console.print("\1hEND\1n\1c: Go to the last item on the screen");
console.crlf();
console.print("\1hF\1n\1c: Go to the first page");
console.crlf();
console.print("\1hL\1n\1c: Go to the last page");
console.crlf();
}
console.crlf();
console.print("Additional keyboard commands:");
console.crlf();
console.print("\1k\1hÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ");
console.crlf();
console.print("\1n\1c\1h?\1n\1c: Show this help screen");
console.crlf();
console.print("\1hQ\1n\1c: Quit");
console.crlf();
}
// Builds sub-board printf format information for a message group.
// The widths of the description & # messages columns are calculated
// based on the greatest number of messages in a sub-board for the
// message group.
//
// Parameters:
// pGrpIndex: The index of the message group
function DigDistMsgReader_BuildSubBoardPrintfInfoForGrp(pGrpIndex)
{
// If the array of sub-board printf strings doesn't contain the printf
// strings for this message group, then figure out the largest number
// of messages in the message group and add the printf strings.
if (typeof(this.subBoardListPrintfInfo[pGrpIndex]) == "undefined")
{
var greatestNumMsgs = getGreatestNumMsgs(pGrpIndex);
this.subBoardListPrintfInfo[pGrpIndex] = new Object();
this.subBoardListPrintfInfo[pGrpIndex].numMsgsLen = greatestNumMsgs.toString().length;
// Sub-board name length: With a # items length of 4, this should be
// 47 for an 80-column display.
this.subBoardListPrintfInfo[pGrpIndex].nameLen = console.screen_columns -
this.areaNumLen -
this.subBoardListPrintfInfo[pGrpIndex].numMsgsLen -
this.dateLen - this.timeLen - 7;
// Create the printf strings
this.subBoardListPrintfInfo[pGrpIndex].printfStr =
" " + this.colors.areaChooserMsgAreaNumColor
+ "%" + this.areaNumLen + "d "
+ this.colors.areaChooserMsgAreaDescColor + "%-"
+ this.subBoardListPrintfInfo[pGrpIndex].nameLen + "s "
+ this.colors.areaChooserMsgAreaNumItemsColor + "%"
+ this.subBoardListPrintfInfo[pGrpIndex].numMsgsLen + "d "
+ this.colors.areaChooserMsgAreaLatestDateColor + "%" + this.dateLen + "s "
+ this.colors.areaChooserMsgAreaLatestTimeColor + "%" + this.timeLen + "s";
this.subBoardListPrintfInfo[pGrpIndex].highlightPrintfStr =
"\1n" + this.colors.areaChooserMsgAreaBkgHighlightColor + " "
+ "\1n" + this.colors.areaChooserMsgAreaBkgHighlightColor
+ this.colors.areaChooserMsgAreaNumHighlightColor
+ "%" + this.areaNumLen + "d \1n"
+ this.colors.areaChooserMsgAreaBkgHighlightColor
+ this.colors.areaChooserMsgAreaDescHighlightColor + "%-"
+ this.subBoardListPrintfInfo[pGrpIndex].nameLen + "s \1n"
+ this.colors.areaChooserMsgAreaBkgHighlightColor
+ this.colors.areaChooserMsgAreaNumItemsHighlightColor + "%"
+ this.subBoardListPrintfInfo[pGrpIndex].numMsgsLen + "d \1n"
+ this.colors.areaChooserMsgAreaBkgHighlightColor
+ this.colors.areaChooserMsgAreaDateHighlightColor + "%" + this.dateLen + "s \1n"
+ this.colors.areaChooserMsgAreaBkgHighlightColor
+ this.colors.areaChooserMsgAreaTimeHighlightColor + "%" + this.timeLen + "s\1n";
}
}
// Returns an array of strings containing extended message header information,
// such as the kludge lines (for FidoNet-style networks), etc.
// For each kludge line, there will be a label string for the info line, the
// info line itself (wrapped to fit the message area width), then a blank
// line (except for the last kludge line). The info lines that this method
// retrieves will only be retrieved if they exist in the given message header.
//
// Parameters:
// pMsgHdr: A message header
// pKludgeOnly: Boolean - Whether or not to only get the kludge lines. If false,
// then all header fields will be retrieved.
//
// Return value: An array of strings containing the extended message header information
function DigDistMsgReader_GetExtdMsgHdrInfo(pMsgHdr, pKludgeOnly)
{
// If pMsgHdr is not valid, then just return an empty array.
if (typeof(pMsgHdr) != "object")
return new Array();
// Get the message header with fields expanded so we can get the most info possible.
var msgHdr = this.GetMsgHdrByAbsoluteNum(pMsgHdr.number, true);
if (msgHdr == null)
return new Array();
var msgHdrInfoLines = new Array();
var hdrInfoLineFields = new Array();
var kludgeOnly = (typeof(pKludgeOnly) == "boolean" ? pKludgeOnly : false);
if (kludgeOnly)
{
hdrInfoLineFields.push({ field: "ftn_msgid", label: "MSG ID:" });
hdrInfoLineFields.push({ field: "X-FTN-MSGID", label: "MSG ID:" });
hdrInfoLineFields.push({ field: "ftn_reply", label: "Reply ID:" });
hdrInfoLineFields.push({ field: "X-FTN-REPLY", label: "Reply ID:" });
hdrInfoLineFields.push({ field: "ftn_area", label: "Area tag:" });
hdrInfoLineFields.push({ field: "X-FTN-AREA", label: "Area tag:" });
hdrInfoLineFields.push({ field: "ftn_flags", label: "Flags:" });
hdrInfoLineFields.push({ field: "ftn_pid", label: "Program ID:" });
hdrInfoLineFields.push({ field: "ftn_tid", label: "Tosser ID:" });
hdrInfoLineFields.push({ field: "X-FTN-TID", label: "Tosser ID:" });
hdrInfoLineFields.push({ field: "X-FTN-Kludge", label: "Kludge:" });
hdrInfoLineFields.push({ field: "X-FTN-SEEN-BY", label: "Seen-By:" });
hdrInfoLineFields.push({ field: "X-FTN-PATH", label: "Path:" });
hdrInfoLineFields.push({ field: "when_written_time", label: "When written time:" });
hdrInfoLineFields.push({ field: "when_imported_time", label: "When imported time:" });
}
// This function returns the number of non-blank lines in a header info array.
//
// Return value: An object with the following properties:
// numNonBlankLines: The number of non-blank lines in the array
// firstNonBlankLineIdx: The index of the first non-blank line
// lastNonBlankLineIdx: The index of the last non-blank line
function findHdrFieldDataArrayNonBlankLines(pHdrArray)
{
var retObj = new Object();
retObj.numNonBlankLines = 0;
retObj.firstNonBlankLineIdx = -1;
retObj.lastNonBlankLineIdx = -1;
for (var lineIdx = 0; lineIdx < pHdrArray.length; ++lineIdx)
if (pHdrArray[lineIdx].length > 0)
++retObj.numNonBlankLines;
if (retObj.firstNonBlankLineIdx == -1)
retObj.firstNonBlankLineIdx = lineIdx;
retObj.lastNonBlankLineIdx = lineIdx;
11576
11577
11578
11579
11580
11581
11582
11583
11584
11585
11586
11587
11588
11589
11590
11591
11592
11593
11594
11595
11596
11597
11598
return retObj;
}
// Counts the number of elements in a header field_list array with the
// same type, starting at a given index.
//
// Parameters:
// pFieldList: The field_list array in a message header
// pStartIdx: The index of the starting element to start counting at
//
// Return value: The number of elements with the same type as the start index element
function fieldListCountSameTypes(pFieldList, pStartIdx)
{
if (typeof(pFieldList) == "undefined")
return 0;
if (typeof(pStartIdx) != "number")
return 0;
if ((pStartIdx < 0) || (pStartIdx >= pFieldList.length))
return 0;
var itemCount = 1;
for (var idx = pStartIdx+1; idx < pFieldList.length; ++idx)
if (pFieldList[idx].type == pFieldList[pStartIdx].type)
++itemCount;
else
break;
}
return itemCount;
}
// Get the header fields
var addTheField = true;
var customFieldLabel = "";
var propCounter = 1;
for (var prop in msgHdr)
{
addTheField = true;
customFieldLabel = "";
if (prop == "field_list")
{
var hdrFieldLabel = "";
var lastHdrFieldLabel = null;
var addBlankLineAfterIdx = -1;
for (var fieldI = 0; fieldI < msgHdr.field_list.length; ++fieldI)
{
// TODO: Some field types can be in the array multiple times but only
// the last is valid. For those, only get the last one:
// 32 (Reply To)
// 33 (Reply To agent)
// 34 (Reply To net type)
// 35 (Reply To net address)
// 36 (Reply To extended)
// 37 (Reply To position)
// 38 (Reply To Organization)
hdrFieldLabel = "\1n" + this.colors.hdrLineLabelColor + msgHdrFieldListTypeToLabel(msgHdr.field_list[fieldI].type) + "\1n";
var infoLineWrapped = msgHdr.field_list[fieldI].data;
var infoLineWrappedArray = lfexpand(infoLineWrapped).split("\r\n");
var hdrArrayNonBlankLines = findHdrFieldDataArrayNonBlankLines(infoLineWrappedArray);
if (hdrArrayNonBlankLines.numNonBlankLines > 0)
{
if (hdrArrayNonBlankLines.numNonBlankLines == 1)
{
var addExtraBlankLineAtEnd = false;
var hdrItem = "\1n" + this.colors.hdrLineValueColor + infoLineWrappedArray[hdrArrayNonBlankLines.firstNonBlankLineIdx] + "\1n";
// If the header field label is different, then add it to the
// header info lines
if ((lastHdrFieldLabel == null) || (hdrFieldLabel != lastHdrFieldLabel))
{
var numFieldItemsWithSameType = fieldListCountSameTypes(msgHdr.field_list, fieldI);
if (numFieldItemsWithSameType > 1)
{
msgHdrInfoLines.push("");
msgHdrInfoLines.push(hdrFieldLabel);
addExtraBlankLineAtEnd = true;
addBlankLineAfterIdx = fieldI + numFieldItemsWithSameType - 1;
}
else
{
hdrItem = hdrFieldLabel + " " + hdrItem;
numFieldItemsWithSameType = -1;
}
}
if (strip_ctrl(hdrItem).length < this.msgAreaWidth)
11662
11663
11664
11665
11666
11667
11668
11669
11670
11671
11672
11673
11674
11675
11676
11677
11678
11679
11680
11681
11682
11683
msgHdrInfoLines.push(hdrItem);
else
{
// If the header field label is different, then add a blank line
// to the header info lines
if ((lastHdrFieldLabel == null) || (hdrFieldLabel != lastHdrFieldLabel))
msgHdrInfoLines.push("");
msgHdrInfoLines.push(hdrFieldLabel);
msgHdrInfoLines.push(infoLineWrappedArray[hdrArrayNonBlankLines.firstNonBlankLineIdx]);
if ((lastHdrFieldLabel == null) || (hdrFieldLabel != lastHdrFieldLabel))
msgHdrInfoLines.push("");
}
}
else
{
// If the header field label is different, then add it to the
// header info lines
if ((lastHdrFieldLabel == null) || (hdrFieldLabel != lastHdrFieldLabel))
{
msgHdrInfoLines.push("");
msgHdrInfoLines.push(hdrFieldLabel + "!");
}
var infoLineWrapped = msgHdr.field_list[fieldI].data;
var infoLineWrappedArray = lfexpand(infoLineWrapped).split("\r\n");
for (var lineIdx = 0; lineIdx < infoLineWrappedArray.length; ++lineIdx)
{
if (infoLineWrappedArray[lineIdx].length > 0)
msgHdrInfoLines.push(infoLineWrappedArray[lineIdx]);
}
// If the header field label is different, then add a blank line to the
// header info lines
if ((lastHdrFieldLabel == null) || (hdrFieldLabel != lastHdrFieldLabel))
msgHdrInfoLines.push("");
}
if (addBlankLineAfterIdx == fieldI)
msgHdrInfoLines.push("");
}

nightfox
committed
lastHdrFieldLabel = hdrFieldLabel;
else
// See if we should add this field
addTheField = true;
if (hdrInfoLineFields.length > 0)
addTheField = false;
for (var infoLineFieldIdx = 0; infoLineFieldIdx < hdrInfoLineFields.length; ++infoLineFieldIdx)
if (prop == hdrInfoLineFields[infoLineFieldIdx].field)

nightfox
committed
{
addTheField = true;
customFieldLabel = hdrInfoLineFields[infoLineFieldIdx].label;
break;
if (!addTheField)
continue;
var propLabel = "";
if (customFieldLabel.length > 0)
propLabel = "\1n" + this.colors.hdrLineLabelColor + customFieldLabel + "\1n";

nightfox
committed
// Remove underscores from the property for the label
propLabel = prop.replace(/_/g, " ");

nightfox
committed
// Apply good-looking capitalization to the property label
if ((propLabel == "id") || (propLabel == "ftn tid"))
propLabel = propLabel.toUpperCase();
else if (propLabel == "ftn area")
propLabel = "FTN Area";
else if (propLabel == "ftn pid")
propLabel = "Program ID";
else if (propLabel == "thread id")
propLabel = "Thread ID";
else if (propLabel == "attr")
propLabel = "Attributes";
else if (propLabel == "auxattr")
propLabel = "Auxiliary attributes";
else if (propLabel == "netattr")
propLabel = "Network attributes";

nightfox
committed
else
propLabel = capitalizeFirstChar(propLabel);
// Add the label color and trailing colon to the label text
propLabel = "\1n" + this.colors.hdrLineLabelColor + propLabel + ":\1n";
}
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)
11776
11777
11778
11779
11780
11781
11782
11783
11784
11785
11786
11787
11788
11789
11790
11791
11792
11793
11794
11795
11796
11797
11798
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.
function DigDistMsgReader_GetMsgInfoForEnhancedReader(pMsgHdr, pWordWrap, pDetermineAttachments,
pGetB64Data, pMsgBody, pMsgHasANSICodes)
{
var retObj = new Object();
var determineAttachments = true;
if (typeof(pDetermineAttachments) == "boolean")
determineAttachments = pDetermineAttachments;
var getB64Data = true;
if (typeof(pGetB64Data) == "boolean")
getB64Data = pGetB64Data;
var msgBody = (typeof(pMsgBody) == "string" ? pMsgBody : this.msgbase.get_msg_body(true, pMsgHdr.offset));
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);
11913
11914
11915
11916
11917
11918
11919
11920
11921
11922
11923
11924
11925
11926
11927
11928
11929
11930
11931
11932
11933
11934
11935
11936
11937
11938
11939
11940
11941
11942
11943
11944
11945
11946
11947
11948
11949
11950
11951
11952
11953
11954
11955
11956
11957
11958
// 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.
retObj.displayFrame = null;
retObj.displayFrameScrollbar = null;
var msgHasANSICodes = (typeof(pMsgHasANSICodes) == "boolean" ? pMsgHasANSICodes : textHasANSICodes(retObj.msgText));
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 ANSITempDirExists = false;
var readerTmpOutputDir = backslash(system.node_dir + "DDMsgReaderANSIMsgTemp");
if (!file_exists(readerTmpOutputDir))
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);
}
}
11974
11975
11976
11977
11978
11979
11980
11981
11982
11983
11984
11985
11986
11987
11988
11989
11990
11991
11992
11993
11994
11995
11996
11997
11998
11999
12000
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;