Newer
Older
msgBase.close();
subBoardArray.push(subBoardInfo);
}
// Free some memory?
delete msgBase;
10007
10008
10009
10010
10011
10012
10013
10014
10015
10016
10017
10018
10019
10020
10021
10022
10023
10024
10025
10026
10027
10028
10029
10030
10031
10032
10033
10034
10035
10036
10037
10038
10039
10040
10041
10042
10043
10044
10045
10046
10047
10048
10049
10050
10051
10052
// Possibly sort the sub-board list.
if (pSortType == "dateAsc")
{
subBoardArray.sort(function(pA, pB)
{
// Return -1, 0, or 1, depending on whether pA's date comes
// before, is equal to, or comes after pB's date.
var returnValue = 0;
if (pA.newestPostDate < pB.newestPostDate)
returnValue = -1;
else if (pA.newestPostDate > pB.newestPostDate)
returnValue = 1;
return returnValue;
});
}
else if (pSortType == "dateDesc")
{
subBoardArray.sort(function(pA, pB)
{
// Return -1, 0, or 1, depending on whether pA's date comes
// after, is equal to, or comes before pB's date.
var returnValue = 0;
if (pA.newestPostDate > pB.newestPostDate)
returnValue = -1;
else if (pA.newestPostDate < pB.newestPostDate)
returnValue = 1;
return returnValue;
});
}
else if (pSortType == "description")
{
// Binary safe string comparison
//
// version: 909.322
// discuss at: http://phpjs.org/functions/strcmp // + original by: Waldo Malqui Silva
// + input by: Steve Hilder
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + revised by: gorthaur
// * example 1: strcmp( 'waldo', 'owald' ); // * returns 1: 1
// * example 2: strcmp( 'owald', 'waldo' );
// * returns 2: -1
subBoardArray.sort(function(pA, pB)
{
return ((pA.description == pB.description) ? 0 : ((pA.description > pB.description) ? 1 : -1));
});
}
10054
10055
10056
10057
10058
10059
10060
10061
10062
10063
10064
10065
10066
10067
10068
10069
10070
10071
10072
10073
10074
10075
10076
10077
10078
10079
10080
10081
10082
10083
10084
10085
10086
10087
10088
10089
10090
10091
10092
10093
// 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, true);
// 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);
}
}
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;
}
}
10111
10112
10113
10114
10115
10116
10117
10118
10119
10120
10121
10122
10123
10124
10125
10126
10127
10128
10129
10130
}
//////////////////////////////////////////////
// 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");
10209
10210
10211
10212
10213
10214
10215
10216
10217
10218
10219
10220
10221
10222
10223
10224
10225
10226
10227
10228
}
//////////////////////////////////////////////////
// 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.gotoxy(29, 1);
console.print("\1n" + this.colors.areaChooserMsgAreaHeaderColor + pPageNum + " of " +
pNumPages + ") ");
}
else
{
console.gotoxy(51, 1);
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)
{
10265
10266
10267
10268
10269
10270
10271
10272
10273
10274
10275
10276
10277
10278
10279
10280
10281
10282
10283
10284
10285
10286
10287
10288
10289
10290
// 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)
{
10338
10339
10340
10341
10342
10343
10344
10345
10346
10347
10348
10349
10350
10351
10352
10353
10354
10355
10356
10357
10358
10359
10360
10361
10362
10363
10364
10365
10366
10367
10368
10369
10370
10371
10372
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, true);
// 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);
}
}
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;
}
10384
10385
10386
10387
10388
10389
10390
10391
10392
10393
10394
10395
10396
10397
10398
10399
10400
10401
10402
10403
10404
10405
10406
10407
10408
10409
10410
10411
10412
10413
10414
10415
10416
10417
10418
10419
10420
10421
10422
10423
10424
10425
10426
10427
10428
10429
10430
10431
10432
10433
10434
10435
10436
10437
10438
10439
10440
10441
10442
10443
10444
10445
10446
10447
10448
10449
10450
10451
10452
10453
10454
10455
10456
10457
10458
10459
10460
10461
10462
10463
10464
10465
10466
10467
10468
10469
10470
10471
10472
10473
10474
10475
10476
10477
10478
10479
10480
10481
10482
10483
10484
10485
10486
10487
10488
10489
10490
10491
10492
10493
10494
10495
10496
10497
10498
10499
10500
}
///////////////////////////////////////////////
// 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();
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;
10567
10568
10569
10570
10571
10572
10573
10574
10575
10576
10577
10578
10579
10580
10581
10582
10583
10584
10585
10586
10587
10588
10589
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)
10591
10592
10593
10594
10595
10596
10597
10598
10599
10600
10601
10602
10603
10604
10605
10606
10607
10608
10609
10610
10611
10612
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 pMsgHdr)
{
addTheField = true;
customFieldLabel = "";
if (prop == "field_list")
{
var hdrFieldLabel = "";
var lastHdrFieldLabel = null;
var addBlankLineAfterIdx = -1;
for (var fieldI = 0; fieldI < pMsgHdr.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(pMsgHdr.field_list[fieldI].type) + "\1n";
// New:
var infoLineWrapped = pMsgHdr.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";
10635
10636
10637
10638
10639
10640
10641
10642
10643
10644
10645
10646
10647
10648
10649
10650
10651
10652
10653
10654
10655
10656
10657
10658
10659
10660
10661
10662
10663
10664
10665
10666
10667
10668
10669
10670
10671
10672
10673
10674
10675
10676
10677
10678
10679
10680
10681
10682
10683
10684
10685
10686
10687
10688
10689
10690
10691
10692
// If the header field label is different, then add it to the
// header info lines
if ((lastHdrFieldLabel == null) || (hdrFieldLabel != lastHdrFieldLabel))
{
var numFieldItemsWithSameType = fieldListCountSameTypes(pMsgHdr.field_list, fieldI);
if (numFieldItemsWithSameType > 1)
{
msgHdrInfoLines.push("");
msgHdrInfoLines.push(hdrFieldLabel);
addExtraBlankLineAtEnd = true;
addBlankLineAfterIdx = fieldI + numFieldItemsWithSameType - 1;
}
else
{
hdrItem = hdrFieldLabel + " " + hdrItem;
numFieldItemsWithSameType = -1;
}
}
if (hdrItem.length < this.msgAreaWidth)
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 = pMsgHdr.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("");
}
// Old:
/*

nightfox
committed
// 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 = pMsgHdr.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]);
}
*/

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 = "\1n" + this.colors.hdrLineLabelColor + prop.replace(/_/g, " ");
// New:

nightfox
committed
// Apply good-looking capitalization to the property label
if ((propLabel == "id") || (propLabel == "ftn tid"))
propLabel = "\1n" + this.colors.hdrLineLabelColor + propLabel.toUpperCase() + ":\1n";

nightfox
committed
else if (propLabel == "ftn_area")
propLabel = "\1n" + this.colors.hdrLineLabelColor + "FTN_Area:\1n";

nightfox
committed
else
propLabel = "\1n" + this.colors.hdrLineLabelColor + capitalizeFirstChar(propLabel) + ":\1n";
}
var infoLineWrapped = word_wrap(pMsgHdr[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)
itemValue = "\1n" + this.colors.hdrLineValueColor + infoLineWrappedArray[lineIdx] + "\1n";
if (prop == "when_written_time")
{
//itemValue = "\1n" + this.colors.hdrLineValueColor + system.timestr(pMsgHdr.when_written_time) + "\1n";
itemValue = "\1n" + this.colors.hdrLineValueColor + system.timestr(pMsgHdr.when_written_time) + " "
+ system.zonestr(pMsgHdr.when_written_zone) + "\1n";
}
else if (prop == "when_imported_time")
{
//itemValue = "\1n" + this.colors.hdrLineValueColor + system.timestr(pMsgHdr.when_imported_time) + "\1n";
itemValue = "\1n" + this.colors.hdrLineValueColor + system.timestr(pMsgHdr.when_imported_time) + " "
+ system.zonestr(pMsgHdr.when_imported_zone) + "\1n";
}
else if ((prop == "when_imported_zone") || (prop == "when_written_zone"))
itemValue = "\1n" + this.colors.hdrLineValueColor + system.zonestr(pMsgHdr[prop]) + "\1n";
10769
10770
10771
10772
10773
10774
10775
10776
10777
10778
10779
10780
10781
10782
10783
10784
10785
10786
10787
10788
10789
10790
10791
10792
10793
10794
var hdrItem = propLabel + " " + itemValue;
if (hdrItem.length < this.msgAreaWidth)
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("");
}
10797
10798
10799
10800
10801
10802
10803
10804
10805
10806
10807
10808
10809
10810
10811
10812
10813
10814
// Old:
/*
// Apply good-looking capitalization to the property label
if ((propLabel == "id") || (propLabel == "ftn tid"))
msgHdrInfoLines.push(propLabel.toUpperCase() + ":");
else if (propLabel == "ftn_area")
msgHdrInfoLines.push("FTN_Area:");
else
msgHdrInfoLines.push(capitalizeFirstChar(propLabel) + ":");
var infoLineWrapped = word_wrap(pMsgHdr[prop], this.msgAreaWidth);
var infoLineWrappedArray = lfexpand(infoLineWrapped).split("\r\n");
for (var lineIdx = 0; lineIdx < infoLineWrappedArray.length; ++lineIdx)
{
if (infoLineWrappedArray[lineIdx].length > 0)
msgHdrInfoLines.push(infoLineWrappedArray[lineIdx]);
}
*/
}

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);
10926
10927
10928
10929
10930
10931
10932
10933
10934
10935
10936
10937
10938
10939
10940
10941
10942
10943
10944
10945
10946
10947
10948
10949
10950
10951
10952
10953
10954
10955
10956
10957
10958
10959
10960
10961
10962
10963
10964
10965
10966
10967
10968
10969
10970
10971
// 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);
}
}
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);