Newer
Older
// pWidth: The width of the text area
// pHeight: The height of the text area
// pPostWriteCurX: The X location for the cursor after writing the message
// lines
// pPostWriteCurY: The Y location for the cursor after writing the message
// lines
// pScrollUpdateFn: A function that the caller can provide for updating the
// scroll position. This function has one parameter:
// - fractionToLastPage: The fraction of the top index divided
// by the top index for the last page (basically, the progress
// to the last page).
//
// Return value: An object with the following properties:
// lastKeypress: The last key pressed by the user (a string)
// topLineIdx: The new top line index of the text lines, in case of scrolling
function scrollTextLines(pTxtLines, pTopLineIdx, pTxtAttrib, pWriteTxtLines, pTopLeftX, pTopLeftY,
pWidth, pHeight, pPostWriteCurX, pPostWriteCurY, pScrollUpdateFn)
{
// Variables for the top line index for the last page, scrolling, etc.
var topLineIdxForLastPage = pTxtLines.length - pHeight;
if (topLineIdxForLastPage < 0)
topLineIdxForLastPage = 0;
var msgFractionShown = pHeight / pTxtLines.length;
if (msgFractionShown > 1)
msgFractionShown = 1.0;
var fractionToLastPage = 0;
var lastTxtRow = pTopLeftY + pHeight - 1;
var txtLineFormatStr = "%-" + pWidth + "s";
var retObj = new Object();
retObj.lastKeypress = "";
retObj.topLineIdx = pTopLineIdx;
15034
15035
15036
15037
15038
15039
15040
15041
15042
15043
15044
15045
15046
15047
15048
15049
15050
15051
15052
15053
15054
15055
15056
15057
15058
15059
15060
15061
15062
15063
15064
15065
15066
var writeTxtLines = pWriteTxtLines;
var continueOn = true;
while (continueOn)
{
// If we are to write the text lines, then write each of them and also
// clear out the rest of the row on the screen
if (writeTxtLines)
{
// If the scroll update function parameter is a function, then calculate
// the fraction to the last page and call the scroll update function.
if (typeof(pScrollUpdateFn) == "function")
{
if (topLineIdxForLastPage != 0)
fractionToLastPage = retObj.topLineIdx / topLineIdxForLastPage;
pScrollUpdateFn(fractionToLastPage);
}
var screenY = pTopLeftY;
for (var lineIdx = retObj.topLineIdx; (lineIdx < pTxtLines.length) && (screenY <= lastTxtRow); ++lineIdx)
{
console.gotoxy(pTopLeftX, screenY++);
// Print the text line, then clear the rest of the line
console.print(pTxtAttrib + pTxtLines[lineIdx]);
printf("\1n%" + +(pWidth - console.strlen(pTxtLines[lineIdx])) + "s", "");
}
// If there are still some lines left in the message reading area, then
// clear the lines.
console.print("\1n" + pTxtAttrib);
while (screenY <= lastTxtRow)
{
console.gotoxy(pTopLeftX, screenY++);
printf(txtLineFormatStr, "");
}
}
15068
15069
15070
15071
15072
15073
15074
15075
15076
15077
15078
15079
15080
15081
15082
15083
15084
15085
15086
15087
15088
15089
15090
15091
15092
15093
15094
15095
15096
15097
15098
15099
15100
15101
15102
15103
15104
15105
15106
15107
15108
15109
15110
15111
15112
15113
15114
15115
15116
15117
15118
15119
15120
15121
15122
15123
15124
15125
15126
15127
15128
15129
15130
15131
15132
15133
15134
15135
15136
15137
15138
15139
15140
15141
15142
15143
15144
15145
15146
15147
15148
15149
15150
15151
15152
15153
15154
15155
15156
15157
15158
15159
15160
15161
15162
15163
15164
15165
15166
15167
15168
15169
writeTxtLines = false;
// Get a keypress from the user and take action based on it
console.gotoxy(pPostWriteCurX, pPostWriteCurY);
retObj.lastKeypress = getKeyWithESCChars(K_UPPER|K_NOCRLF|K_NOECHO|K_NOSPIN);
switch (retObj.lastKeypress)
{
case KEY_UP:
if (retObj.topLineIdx > 0)
{
--retObj.topLineIdx;
writeTxtLines = true;
}
break;
case KEY_DOWN:
if (retObj.topLineIdx < topLineIdxForLastPage)
{
++retObj.topLineIdx;
writeTxtLines = true;
}
break;
case KEY_PAGE_DOWN: // Next page
if (retObj.topLineIdx < topLineIdxForLastPage)
{
retObj.topLineIdx += pHeight;
if (retObj.topLineIdx > topLineIdxForLastPage)
retObj.topLineIdx = topLineIdxForLastPage;
writeTxtLines = true;
}
break;
case KEY_PAGE_UP: // Previous page
if (retObj.topLineIdx > 0)
{
retObj.topLineIdx -= pHeight;
if (retObj.topLineIdx < 0)
retObj.topLineIdx = 0;
writeTxtLines = true;
}
break;
case KEY_HOME: // First page
if (retObj.topLineIdx > 0)
{
retObj.topLineIdx = 0;
writeTxtLines = true;
}
break;
case KEY_END: // Last page
if (retObj.topLineIdx < topLineIdxForLastPage)
{
retObj.topLineIdx = topLineIdxForLastPage;
writeTxtLines = true;
}
break;
default:
continueOn = false;
break;
}
}
return retObj;
}
// Displays a Frame on the screen and allows scrolling through it with the up &
// down arrow keys, PageUp, PageDown, HOME, and END.
//
// Parameters:
// pFrame: A Frame object to display & scroll through
// pScrollbar: A ScrollBar object associated with the Frame object
// pTopLineIdx: The index of the text line to display at the top
// pTxtAttrib: The attribute(s) to apply to the text lines
// pWriteTxtLines: Boolean - Whether or not to write the text lines (in addition
// to doing the message loop). If false, this will only do the
// the message loop. This parameter is intended as a screen
// refresh optimization.
// pPostWriteCurX: The X location for the cursor after writing the message
// lines
// pPostWriteCurY: The Y location for the cursor after writing the message
// lines
// pScrollUpdateFn: A function that the caller can provide for updating the
// scroll position. This function has one parameter:
// - fractionToLastPage: The fraction of the top index divided
// by the top index for the last page (basically, the progress
// to the last page).
//
// Return value: An object with the following properties:
// lastKeypress: The last key pressed by the user (a string)
// topLineIdx: The new top line index of the text lines, in case of scrolling
function scrollFrame(pFrame, pScrollbar, pTopLineIdx, pTxtAttrib, pWriteTxtLines, pPostWriteCurX,
pPostWriteCurY, pScrollUpdateFn)
{
// Variables for the top line index for the last page, scrolling, etc.
var topLineIdxForLastPage = pFrame.data_height - pFrame.height;
if (topLineIdxForLastPage < 0)
topLineIdxForLastPage = 0;
var retObj = new Object();
retObj.lastKeypress = "";
retObj.topLineIdx = pTopLineIdx;
if (pTopLineIdx > 0)
pFrame.scrollTo(0, pTopLineIdx);
var writeTxtLines = pWriteTxtLines;

nightfox
committed
if (writeTxtLines)
{
pFrame.invalidate(); // Force drawing on the next call to draw() or cycle()
pFrame.cycle();
//pFrame.draw();
}
var cycleFrame = true;
var continueOn = true;
while (continueOn)
{
// If we are to write the text lines, then draw the frame.
// TODO: Do we really need this? Will this be different from
// scrollTextLines()?
//if (writeTxtLines)
// pFrame.draw();
if (cycleFrame)
{
// Invalidate the frame to force it to redraw everything, as a
// workaround to clear the background before writing again
// TODO: I might want to remove this invalidate() later when
// Frame is fixed to redraw better on scrolling.
pFrame.invalidate();
// Cycle the scrollbar & frame to get them to scroll

nightfox
committed
if (pScrollbar != null)
pScrollbar.cycle();

nightfox
committed
pFrame.cycle();
15198
15199
15200
15201
15202
15203
15204
15205
15206
15207
15208
15209
15210
15211
15212
15213
15214
15215
15216
15217
15218
15219
15220
15221
15222
15223
15224
15225
15226
15227
15228
15229
15230
15231
15232
15233
15234
15235
15236
15237
15238
15239
15240
15241
15242
15243
15244
15245
15246
15247
15248
15249
15250
15251
15252
15253
15254
15255
15256
15257
15258
15259
15260
15261
15262
15263
15264
15265
15266
15267
15268
}
writeTxtLines = false;
cycleFrame = false;
// Get a keypress from the user and take action based on it
console.gotoxy(pPostWriteCurX, pPostWriteCurY);
retObj.lastKeypress = getKeyWithESCChars(K_UPPER|K_NOCRLF|K_NOECHO|K_NOSPIN);
switch (retObj.lastKeypress)
{
case KEY_UP:
if (retObj.topLineIdx > 0)
{
pFrame.scroll(0, -1);
--retObj.topLineIdx;
cycleFrame = true;
writeTxtLines = true;
}
break;
case KEY_DOWN:
if (retObj.topLineIdx < topLineIdxForLastPage)
{
pFrame.scroll(0, 1);
cycleFrame = true;
++retObj.topLineIdx;
writeTxtLines = true;
}
break;
case KEY_PAGE_DOWN: // Next page
if (retObj.topLineIdx < topLineIdxForLastPage)
{
//pFrame.scroll(0, pFrame.height);
retObj.topLineIdx += pFrame.height;
if (retObj.topLineIdx > topLineIdxForLastPage)
retObj.topLineIdx = topLineIdxForLastPage;
pFrame.scrollTo(1, retObj.topLineIdx+1);
cycleFrame = true;
writeTxtLines = true;
}
break;
case KEY_PAGE_UP: // Previous page
if (retObj.topLineIdx > 0)
{
//pFrame.scroll(0, -(pFrame.height));
retObj.topLineIdx -= pFrame.height;
if (retObj.topLineIdx < 0)
retObj.topLineIdx = 0;
pFrame.scrollTo(1, retObj.topLineIdx+1);
cycleFrame = true;
writeTxtLines = true;
}
break;
case KEY_HOME: // First page
//pFrame.home();
pFrame.scrollTo(1, 1);
cycleFrame = true;
retObj.topLineIdx = 0;
break;
case KEY_END: // Last page
//pFrame.end();
pFrame.scrollTo(1, topLineIdxForLastPage+1);
cycleFrame = true;
retObj.topLineIdx = topLineIdxForLastPage;
break;
default:
continueOn = false;
break;
}
}
return retObj;
15269
15270
15271
15272
15273
15274
15275
15276
15277
15278
15279
15280
15281
15282
15283
15284
15285
15286
15287
15288
15289
15290
15291
15292
15293
15294
15295
15296
15297
15298
15299
15300
15301
15302
15303
15304
15305
15306
15307
15308
15309
15310
15311
15312
15313
15314
15315
15316
15317
15318
15319
15320
15321
15322
15323
15324
15325
15326
15327
15328
15329
15330
15331
15332
15333
15334
15335
15336
15337
15338
15339
15340
15341
15342
15343
15344
15345
15346
15347
15348
15349
15350
15351
15352
15353
15354
15355
15356
15357
15358
15359
15360
15361
15362
15363
15364
15365
15366
15367
15368
15369
15370
15371
15372
15373
15374
15375
15376
15377
15378
15379
15380
15381
15382
15383
15384
15385
15386
15387
15388
15389
15390
15391
15392
15393
15394
15395
15396
15397
15398
15399
15400
15401
15402
15403
15404
15405
15406
15407
15408
15409
15410
15411
15412
15413
15414
15415
15416
15417
15418
15419
15420
15421
15422
15423
15424
15425
15426
15427
15428
15429
15430
15431
15432
15433
15434
15435
15436
15437
15438
15439
15440
15441
15442
15443
15444
15445
15446
15447
15448
15449
15450
15451
15452
15453
15454
15455
15456
15457
15458
15459
15460
15461
15462
15463
15464
15465
15466
15467
15468
15469
15470
15471
15472
15473
15474
15475
15476
15477
15478
15479
15480
15481
15482
15483
15484
15485
15486
15487
15488
15489
15490
15491
15492
15493
15494
15495
15496
15497
15498
15499
15500
15501
15502
15503
15504
15505
15506
}
// Finds the (1-based) page number of an item by number (1-based). If no page
// is found, then the return value will be 0.
//
// Parameters:
// pItemNum: The item number (1-based)
// pNumPerPage: The number of items per page
// pTotoalNum: The total number of items in the list
// pReverseOrder: Boolean - Whether or not the list is in reverse order. If not specified,
// this will default to false.
//
// Return value: The page number (1-based) of the item number. If no page is found,
// the return value will be 0.
function findPageNumOfItemNum(pItemNum, pNumPerPage, pTotalNum, pReverseOrder)
{
if ((typeof(pItemNum) != "number") || (typeof(pNumPerPage) != "number") || (typeof(pTotalNum) != "number"))
return 0;
if ((pItemNum < 1) || (pItemNum > pTotalNum))
return 0;
var reverseOrder = (typeof(pReverseOrder) == "boolean" ? pReverseOrder : false);
var itemPageNum = 0;
if (reverseOrder)
{
var pageNum = 1;
for (var topNum = pTotalNum; ((topNum > 0) && (itemPageNum == 0)); topNum -= pNumPerPage)
{
if ((pItemNum <= topNum) && (pItemNum >= topNum-pNumPerPage+1))
itemPageNum = pageNum;
++pageNum;
}
}
else // Forward order
itemPageNum = Math.ceil(pItemNum / pNumPerPage);
return itemPageNum;
}
// This function converts a search mode string to one of the defined search value
// constants. If the passed-in mode string is unknown, then the return value will
// be SEARCH_NONE (-1).
//
// Parameters:
// pSearchTypeStr: A string describing a search mode ("keyword_search", "from_name_search",
// "to_name_search", "to_user_search", "new_msg_scan", "new_msg_scan_cur_sub",
// "new_msg_scan_cur_grp", "new_msg_scan_all", "to_user_new_scan",
// "to_user_all_scan")
//
// Return value: An integer representing the search value (SEARCH_KEYWORD,
// SEARCH_FROM_NAME, SEARCH_TO_NAME_CUR_MSG_AREA,
// SEARCH_TO_USER_CUR_MSG_AREA), or SEARCH_NONE (-1) if the passed-in
// search type string is unknown.
function searchTypeStrToVal(pSearchTypeStr)
{
if (typeof(pSearchTypeStr) != "string")
return SEARCH_NONE;
var searchTypeInt = SEARCH_NONE;
var modeStr = pSearchTypeStr.toLowerCase();
if (modeStr == "keyword_search")
searchTypeInt = SEARCH_KEYWORD;
else if (modeStr == "from_name_search")
searchTypeInt = SEARCH_FROM_NAME;
else if (modeStr == "to_name_search")
searchTypeInt = SEARCH_TO_NAME_CUR_MSG_AREA;
else if (modeStr == "to_user_search")
searchTypeInt = SEARCH_TO_USER_CUR_MSG_AREA;
else if (modeStr == "new_msg_scan")
searchTypeInt = SEARCH_MSG_NEWSCAN;
else if (modeStr == "new_msg_scan_cur_sub")
searchTypeInt = SEARCH_MSG_NEWSCAN_CUR_SUB;
else if (modeStr == "new_msg_scan_cur_grp")
searchTypeInt = SEARCH_MSG_NEWSCAN_CUR_GRP;
else if (modeStr == "new_msg_scan_all")
searchTypeInt = SEARCH_MSG_NEWSCAN_ALL;
else if (modeStr == "to_user_new_scan")
searchTypeInt = SEARCH_TO_USER_NEW_SCAN;
else if (modeStr == "to_user_new_scan_cur_sub")
searchTypeInt = SEARCH_TO_USER_NEW_SCAN_CUR_SUB;
else if (modeStr == "to_user_new_scan_cur_grp")
searchTypeInt = SEARCH_TO_USER_NEW_SCAN_CUR_GRP;
else if (modeStr == "to_user_new_scan_all")
searchTypeInt = SEARCH_TO_USER_NEW_SCAN_ALL;
else if (modeStr == "to_user_all_scan")
searchTypeInt = SEARCH_ALL_TO_USER_SCAN;
return searchTypeInt;
}
// This function converts a search type value to a string description.
//
// Parameters:
// pSearchType: The search type value to convert
//
// Return value: A string describing the search type value
function searchTypeValToStr(pSearchType)
{
if (typeof(pSearchType) != "number")
return "Unknown (not a number)";
var searchTypeStr = "";
switch (pSearchType)
{
case SEARCH_NONE:
searchTypeStr = "None (SEARCH_NONE)";
break;
case SEARCH_KEYWORD:
searchTypeStr = "Keyword (SEARCH_KEYWORD)";
break;
case SEARCH_FROM_NAME:
searchTypeStr = "'From' name (SEARCH_FROM_NAME)";
break;
case SEARCH_TO_NAME_CUR_MSG_AREA:
searchTypeStr = "'To' name (SEARCH_TO_NAME_CUR_MSG_AREA)";
break;
case SEARCH_TO_USER_CUR_MSG_AREA:
searchTypeStr = "To you (SEARCH_TO_USER_CUR_MSG_AREA)";
break;
case SEARCH_MSG_NEWSCAN:
searchTypeStr = "New message scan (SEARCH_MSG_NEWSCAN)";
break;
case SEARCH_MSG_NEWSCAN_CUR_SUB:
searchTypeStr = "New in current message area (SEARCH_MSG_NEWSCAN_CUR_SUB)";
break;
case SEARCH_MSG_NEWSCAN_CUR_GRP:
searchTypeStr = "New in current message group (SEARCH_MSG_NEWSCAN_CUR_GRP)";
break;
case SEARCH_MSG_NEWSCAN_ALL:
searchTypeStr = "Newscan - All (SEARCH_MSG_NEWSCAN_ALL)";
break;
case SEARCH_TO_USER_NEW_SCAN:
searchTypeStr = "To You new scan (SEARCH_TO_USER_NEW_SCAN)";
break;
case SEARCH_TO_USER_NEW_SCAN_CUR_SUB:
searchTypeStr = "To You new scan, current sub-board (SEARCH_TO_USER_NEW_SCAN_CUR_SUB)";
break;
case SEARCH_TO_USER_NEW_SCAN_CUR_GRP:
searchTypeStr = "To You new scan, current group (SEARCH_TO_USER_NEW_SCAN_CUR_GRP)";
break;
case SEARCH_TO_USER_NEW_SCAN_ALL:
searchTypeStr = "To You new scan, all sub-boards (SEARCH_TO_USER_NEW_SCAN_ALL)";
break;
case SEARCH_ALL_TO_USER_SCAN:
searchTypeStr = "All To You scan (SEARCH_ALL_TO_USER_SCAN)";
break;
default:
searchTypeStr = "Unknown (" + pSearchType + ")";
break;
}
return searchTypeStr;
}
// This function converts a reader mode string to one of the defined reader mode
// value constants. If the passed-in mode string is unknown, then the return value
// will be -1.
//
// Parameters:
// pModeStr: A string describing a reader mode ("read", "reader", "list", "lister")
//
// Return value: An integer representing the reader mode value (READER_MODE_READ,
// READER_MODE_LIST), or -1 if the passed-in mode string is unknown.
function readerModeStrToVal(pModeStr)
{
if (typeof(pModeStr) != "string")
return -1;
var readerModeInt = -1;
var modeStr = pModeStr.toLowerCase();
if ((modeStr == "read") || (modeStr == "reader"))
readerModeInt = READER_MODE_READ;
else if ((modeStr == "list") || (modeStr == "lister"))
readerModeInt = READER_MODE_LIST;
return readerModeInt;
}
// This function returns a boolean to signify whether or not the user's
// terminal supports both high-ASCII characters and ANSI codes.
function canDoHighASCIIAndANSI()
{
//return (console.term_supports(USER_ANSI) && (user.settings & USER_NO_EXASCII == 0));
return (console.term_supports(USER_ANSI));
}
// Searches a given range in an open message base and returns an object with arrays
// containing the message headers (0-based indexed and indexed by message number)
// with the message headers of any found messages.
//
// Parameters:
// pSubCode: The internal code of the message sub-board
// pMsgbase: A message base object in which to search messages
// pSearchType: The type of search to do (one of the SEARCH_ values)
// pSearchString: The string to search for.
// pListingPersonalEmailFromUser: Optional boolean - Whether or not we're listing
// personal email sent by the user. This defaults
// to false.
// pStartIndex: The starting message index (0-based). Optional; defaults to 0.
// pEndIndex: One past the last message index. Optional; defaults to the total number
// of messages.
//
// Return value: An object with the following arrays:
// indexed: A 0-based indexed array of message headers
function searchMsgbase(pSubCode, pMsgbase, pSearchType, pSearchString,
pListingPersonalEmailFromUser, pStartIndex, pEndIndex)
{
var msgHeaders = new Object();
msgHeaders.indexed = new Array();
if ((pSubCode != "mail") && ((typeof(pSearchString) != "string") || !searchTypePopulatesSearchResults(pSearchType)))
return msgHeaders;
var startMsgIndex = 0;
var endMsgIndex = pMsgbase.total_msgs;
if (typeof(pStartIndex) == "number")
{
if ((pStartIndex >= 0) && (pStartIndex < pMsgbase.total_msgs))
startMsgIndex = pStartIndex;
}
if (typeof(pEndIndex) == "number")
{
if ((pEndIndex >= 0) && (pEndIndex > startMsgIndex) && (pEndIndex <= pMsgbase.total_msgs))
endMsgIndex = pEndIndex;
}
// Define a search function for the message field we're going to search
var readingPersonalEmailFromUser = (typeof(pListingPersonalEmailFromUser) == "boolean" ? pListingPersonalEmailFromUser : false);
var matchFn = null;
switch (pSearchType)
{
// It might seem odd to have SEARCH_NONE in here, but it's here because
// when reading personal email, we need to search for messages only to
// the current user.
case SEARCH_NONE:
if (pSubCode == "mail")
{
// Set up the match function slightly differently depending on whether
// we're looking for mail from the current user or to the current user.
if (readingPersonalEmailFromUser)
{
matchFn = function(pSearchStr, pMsgHdr, pMsgBase, pSubBoardCode) {
var msgText = strip_ctrl(pMsgBase.get_msg_body(false, pMsgHdr.number));
return gAllPersonalEmailOptSpecified || msgIsFromUser(pMsgHdr);
}
}
else
{
matchFn = function(pSearchStr, pMsgHdr, pMsgBase, pSubBoardCode) {
var msgText = strip_ctrl(pMsgBase.get_msg_body(false, pMsgHdr.number));
return gAllPersonalEmailOptSpecified || msgIsToUserByNum(pMsgHdr);
}
}
}
break;
case SEARCH_KEYWORD:
matchFn = function(pSearchStr, pMsgHdr, pMsgBase, pSubBoardCode) {
var msgText = strip_ctrl(pMsgBase.get_msg_body(false, pMsgHdr.number));
var keywordFound = ((pMsgHdr.subject.toUpperCase().indexOf(pSearchStr) > -1) || (msgText.toUpperCase().indexOf(pSearchStr) > -1));
if (pSubBoardCode == "mail")
return keywordFound && msgIsToUserByNum(pMsgHdr);
else
return keywordFound;
}
break;
case SEARCH_FROM_NAME:
matchFn = function(pSearchStr, pMsgHdr, pMsgBase, pSubBoardCode) {
var fromNameFound = (pMsgHdr.from.toUpperCase() == pSearchStr.toUpperCase());
if (pSubBoardCode == "mail")
return fromNameFound && (gAllPersonalEmailOptSpecified || msgIsToUserByNum(pMsgHdr));
15535
15536
15537
15538
15539
15540
15541
15542
15543
15544
15545
15546
15547
15548
15549
15550
15551
15552
15553
15554
15555
15556
15557
15558
15559
15560
15561
15562
15563
15564
15565
15566
else
return fromNameFound;
}
break;
case SEARCH_TO_NAME_CUR_MSG_AREA:
matchFn = function(pSearchStr, pMsgHdr, pMsgBase, pSubBoardCode) {
return (pMsgHdr.to.toUpperCase() == pSearchStr);
}
break;
case SEARCH_TO_USER_CUR_MSG_AREA:
case SEARCH_ALL_TO_USER_SCAN:
matchFn = function(pSearchStr, pMsgHdr, pMsgBase, pSubBoardCode) {
// See if the message is not marked as deleted and the 'To' name
// matches the user's handle, alias, and/or username.
return (((pMsgHdr.attr & MSG_DELETE) == 0) && userNameHandleAliasMatch(pMsgHdr.to));
}
break;
case SEARCH_TO_USER_NEW_SCAN:
case SEARCH_TO_USER_NEW_SCAN_CUR_SUB:
case SEARCH_TO_USER_NEW_SCAN_CUR_GRP:
case SEARCH_TO_USER_NEW_SCAN_ALL:
if (pSubCode != "mail")
{
// If pStartIndex or pEndIndex aren't specified, then set
// startMsgIndex to the scan pointer and endMsgIndex to one
// past the index of the last message in the sub-board
if (typeof(pStartIndex) != "number")
{
// First, write some messages to the log if verbose logging is enabled
if (gCmdLineArgVals.verboselogging)
{
writeToSysAndNodeLog("New-to-user scan for " +
subBoardGrpAndName(pSubCode) + " -- Scan pointer: " +
msg_area.sub[pSubCode].scan_ptr);
}
//startMsgIndex = absMsgNumToIdx(pMsgbase, msg_area.sub[pSubCode].last_read);
startMsgIndex = absMsgNumToIdx(pMsgbase, msg_area.sub[pSubCode].scan_ptr);
if (startMsgIndex == -1)
{
msg_area.sub[pSubCode].scan_ptr = 0;
startMsgIndex = 0;
}
else
{
// If this message has been read, then start at the next message.
var startMsgHeader = pMsgbase.get_msg_header(true, startMsgIndex, false);
if ((startMsgHeader.attr & MSG_READ) == MSG_READ)
++startMsgIndex;
}
15584
15585
15586
15587
15588
15589
15590
15591
15592
15593
15594
15595
15596
15597
15598
15599
15600
15601
15602
}
if (typeof(pEndIndex) != "number")
endMsgIndex = (pMsgbase.total_msgs > 0 ? pMsgbase.total_msgs : 0);
}
matchFn = function(pSearchStr, pMsgHdr, pMsgBase, pSubBoardCode) {
// Note: This assumes pSubBoardCode is not "mail" (personal mail).
// See if the message 'To' name matches the user's handle, alias,
// and/or username and is not marked as deleted and is unread.
return (((pMsgHdr.attr & MSG_DELETE) == 0) && ((pMsgHdr.attr & MSG_READ) == 0) && userNameHandleAliasMatch(pMsgHdr.to));
}
break;
case SEARCH_MSG_NEWSCAN:
case SEARCH_MSG_NEWSCAN_CUR_SUB:
case SEARCH_MSG_NEWSCAN_CUR_GRP:
case SEARCH_MSG_NEWSCAN_ALL:
matchFn = function(pSearchStr, pMsgHdr, pMsgBase, pSubBoardCode) {
// Note: This assumes pSubBoardCode is not "mail" (personal mail).
// Get the offset of the last read message and compare it with the
// offset of the given message header
var lastReadMsgHdr = pMsgBase.get_msg_header(false, msg_area.sub[pSubBoardCode].last_read, false);
//var lastReadMsgOffset = (lastReadMsgHdr != null ? lastReadMsgHdr.offset : 0);
var lastReadMsgOffset = (lastReadMsgHdr != null ? this.GetMsgIdx(lastReadMsgHdr.number) : 0);

nightfox
committed
if (lastReadMsgOffset < 0)
lastReadMsgOffset = 0;
//return (pMsgHdr.offset > lastReadMsgOffset);
return (this.GetMsgIdx(pMsgHdr.number) > lastReadMsgOffset);
}
break;
}
// Search the messages
if (matchFn != null)
{
for (var msgIdx = startMsgIndex; msgIdx < endMsgIndex; ++msgIdx)
{
var msgHeader = pMsgbase.get_msg_header(true, msgIdx, false);
// I've seen situations where the message header object is null for
// some reason, so check that before running the search function.
if (msgHeader != null)
{
if (matchFn(pSearchString, msgHeader, pMsgbase, pSubCode))
msgHeaders.indexed.push(msgHeader);
}
}
}
return msgHeaders;
}
// Returns whether or not a message is to the current user (either the current
// logged-in user or the user specified by the userNum command-line argument)
// and is not deleted.
//
// Parameters:
// pMsgHdr: A message header object
//
// Return value: Boolean - Whether or not the message is to the user and is not
// deleted.
function msgIsToUserByNum(pMsgHdr)
{
if (typeof(pMsgHdr) != "object")
return false;
// Return false if the message is marked as deleted
if ((pMsgHdr.attr & MSG_DELETE) == MSG_DELETE)
return false;
var msgIsToUser = false;
// If an alternate user number was specified on the command line, then use that
// user information. Otherwise, use the current logged-in user.
if (gCmdLineArgVals.hasOwnProperty("altUserNum"))
msgIsToUser = (pMsgHdr.to_ext == gCmdLineArgVals.altUserNum);
else
msgIsToUser = (pMsgHdr.to_ext == user.number);
return msgIsToUser;
}
// Returns whether or not a message is from the current user (either the current
// logged-in user or the user specified by the userNum command-line argument)
// and is not deleted.
//
// Parameters:
// pMsgHdr: A message header object
//
// Return value: Boolean - Whether or not the message is from the logged-in user
// and is not deleted.
function msgIsFromUser(pMsgHdr)
{
if (typeof(pMsgHdr) != "object")
return false;
15671
15672
15673
15674
15675
15676
15677
15678
15679
15680
15681
15682
15683
15684
15685
15686
15687
15688
15689
15690
15691
15692
15693
15694
15695
15696
// Return false if the message is marked as deleted
if ((pMsgHdr.attr & MSG_DELETE) == MSG_DELETE)
return false;
var isFromUser = false;
// If an alternate user number was specified on the command line, then use that
// user information. Otherwise, use the current logged-in user.
if (pMsgHdr.hasOwnProperty("from_ext"))
{
if (gCmdLineArgVals.hasOwnProperty("altUserNum"))
isFromUser = (pMsgHdr.from_ext == gCmdLineArgVals.altUserNum);
else
isFromUser = (pMsgHdr.from_ext == user.number);
}
else
{
var hdrFromUpper = pMsgHdr.from.toUpperCase();
if (gCmdLineArgVals.hasOwnProperty("altUserName") && gCmdLineArgVals.hasOwnProperty("altUserAlias"))
isFromUser = ((hdrFromUpper == gCmdLineArgVals.altUserAlias.toUpperCase()) || (hdrFromUpper == gCmdLineArgVals.altUserName.toUpperCase()));
else
isFromUser = ((hdrFromUpper == user.alias.toUpperCase()) || (hdrFromUpper == user.name.toUpperCase()));
}
return isFromUser;
15697
15698
15699
15700
15701
15702
15703
15704
15705
15706
15707
15708
15709
15710
15711
15712
15713
15714
15715
15716
15717
15718
}
/////////////////////////////////////////////////////////////////////////
// Functions for converting other BBS color codes to Synchronet attribute codes
// Converts WWIV attribute codes to Synchronet attribute codes.
//
// Parameters:
// pText: A string containing the text to convert
//
// Return value: The text with the color codes converted
function WWIVAttrsToSyncAttrs(pText)
{
// First, see if the text has any WWIV-style attribute codes at
// all. We'll be performing a bunch of search & replace commands,
// so we don't want to do all that work for nothing.. :)
if (/\x03[0-9]/.test(pText))
{
var text = pText.replace(/\x030/g, "\1n"); // Normal
text = text.replace(/\x031/g, "\1n\1c\1h"); // Bright cyan
text = text.replace(/\x032/g, "\1n\1y\1h"); // Bright yellow
text = text.replace(/\x033/g, "\1n\1m"); // Magenta
text = text.replace(/\x034/g, "\1n\1h\1w\1" + "4"); // Bright white on blue
15720
15721
15722
15723
15724
15725
15726
15727
15728
15729
15730
15731
15732
15733
15734
15735
15736
15737
15738
15739
15740
15741
15742
15743
15744
text = text.replace(/\x035/g, "\1n\1g"); // Green
text = text.replace(/\x036/g, "\1h\1r\1i"); // Bright red, blinking
text = text.replace(/\x037/g, "\1n\1h\1b"); // Bright blue
text = text.replace(/\x038/g, "\1n\1b"); // Blue
text = text.replace(/\x039/g, "\1n\1c"); // Cyan
return text;
}
else
return pText; // No WWIV-style color attribute found, so just return the text.
}
// Converts PCBoard attribute codes to Synchronet attribute codes.
//
// Parameters:
// pText: A string containing the text to convert
//
// Return value: The text with the color codes converted
function PCBoardAttrsToSyncAttrs(pText)
{
// First, see if the text has any PCBoard-style attribute codes at
// all. We'll be performing a bunch of search & replace commands,
// so we don't want to do all that work for nothing.. :)
if (/@[xX][0-9A-Fa-f]{2}/.test(pText))
{
// Black background
15745
15746
15747
15748
15749
15750
15751
15752
15753
15754
15755
15756
15757
15758
15759
15760
15761
15762
var text = pText.replace(/@[xX]00/g, "\1n\1k\1" + "0"); // Black on black
text = text.replace(/@[xX]01/g, "\1n\1b\1" + "0"); // Blue on black
text = text.replace(/@[xX]02/g, "\1n\1g\1" + "0"); // Green on black
text = text.replace(/@[xX]03/g, "\1n\1c\1" + "0"); // Cyan on black
text = text.replace(/@[xX]04/g, "\1n\1r\1" + "0"); // Red on black
text = text.replace(/@[xX]05/g, "\1n\1m\1" + "0"); // Magenta on black
text = text.replace(/@[xX]06/g, "\1n\1y\1" + "0"); // Yellow/brown on black
text = text.replace(/@[xX]07/g, "\1n\1w\1" + "0"); // White on black
text = text.replace(/@[xX]08/g, "\1n\1w\1" + "0"); // White on black
text = text.replace(/@[xX]09/g, "\1n\1w\1" + "0"); // White on black
text = text.replace(/@[xX]08/g, "\1h\1k\1" + "0"); // Bright black on black
text = text.replace(/@[xX]09/g, "\1h\1b\1" + "0"); // Bright blue on black
text = text.replace(/@[xX]0[Aa]/g, "\1h\1g\1" + "0"); // Bright green on black
text = text.replace(/@[xX]0[Bb]/g, "\1h\1c\1" + "0"); // Bright cyan on black
text = text.replace(/@[xX]0[Cc]/g, "\1h\1r\1" + "0"); // Bright red on black
text = text.replace(/@[xX]0[Dd]/g, "\1h\1m\1" + "0"); // Bright magenta on black
text = text.replace(/@[xX]0[Ee]/g, "\1h\1y\1" + "0"); // Bright yellow on black
text = text.replace(/@[xX]0[Ff]/g, "\1h\1w\1" + "0"); // Bright white on black
// Blinking foreground
// Blue background
text = text.replace(/@[xX]10/g, "\1n\1k\1" + "4"); // Black on blue
text = text.replace(/@[xX]11/g, "\1n\1b\1" + "4"); // Blue on blue
text = text.replace(/@[xX]12/g, "\1n\1g\1" + "4"); // Green on blue
text = text.replace(/@[xX]13/g, "\1n\1c\1" + "4"); // Cyan on blue
text = text.replace(/@[xX]14/g, "\1n\1r\1" + "4"); // Red on blue
text = text.replace(/@[xX]15/g, "\1n\1m\1" + "4"); // Magenta on blue
text = text.replace(/@[xX]16/g, "\1n\1y\1" + "4"); // Yellow/brown on blue
text = text.replace(/@[xX]17/g, "\1n\1w\1" + "4"); // White on blue
text = text.replace(/@[xX]18/g, "\1h\1k\1" + "4"); // Bright black on blue
text = text.replace(/@[xX]19/g, "\1h\1b\1" + "4"); // Bright blue on blue
text = text.replace(/@[xX]1[Aa]/g, "\1h\1g\1" + "4"); // Bright green on blue
text = text.replace(/@[xX]1[Bb]/g, "\1h\1c\1" + "4"); // Bright cyan on blue
text = text.replace(/@[xX]1[Cc]/g, "\1h\1r\1" + "4"); // Bright red on blue
text = text.replace(/@[xX]1[Dd]/g, "\1h\1m\1" + "4"); // Bright magenta on blue
text = text.replace(/@[xX]1[Ee]/g, "\1h\1y\1" + "4"); // Bright yellow on blue
text = text.replace(/@[xX]1[Ff]/g, "\1h\1w\1" + "4"); // Bright white on blue
// Green background
text = text.replace(/@[xX]20/g, "\1n\1k\1" + "2"); // Black on green
text = text.replace(/@[xX]21/g, "\1n\1b\1" + "2"); // Blue on green
text = text.replace(/@[xX]22/g, "\1n\1g\1" + "2"); // Green on green
text = text.replace(/@[xX]23/g, "\1n\1c\1" + "2"); // Cyan on green
text = text.replace(/@[xX]24/g, "\1n\1r\1" + "2"); // Red on green
text = text.replace(/@[xX]25/g, "\1n\1m\1" + "2"); // Magenta on green
text = text.replace(/@[xX]26/g, "\1n\1y\1" + "2"); // Yellow/brown on green
text = text.replace(/@[xX]27/g, "\1n\1w\1" + "2"); // White on green
text = text.replace(/@[xX]28/g, "\1h\1k\1" + "2"); // Bright black on green
text = text.replace(/@[xX]29/g, "\1h\1b\1" + "2"); // Bright blue on green
text = text.replace(/@[xX]2[Aa]/g, "\1h\1g\1" + "2"); // Bright green on green
text = text.replace(/@[xX]2[Bb]/g, "\1h\1c\1" + "2"); // Bright cyan on green
text = text.replace(/@[xX]2[Cc]/g, "\1h\1r\1" + "2"); // Bright red on green
text = text.replace(/@[xX]2[Dd]/g, "\1h\1m\1" + "2"); // Bright magenta on green
text = text.replace(/@[xX]2[Ee]/g, "\1h\1y\1" + "2"); // Bright yellow on green
text = text.replace(/@[xX]2[Ff]/g, "\1h\1w\1" + "2"); // Bright white on green
// Cyan background
text = text.replace(/@[xX]30/g, "\1n\1k\1" + "6"); // Black on cyan
text = text.replace(/@[xX]31/g, "\1n\1b\1" + "6"); // Blue on cyan
text = text.replace(/@[xX]32/g, "\1n\1g\1" + "6"); // Green on cyan
text = text.replace(/@[xX]33/g, "\1n\1c\1" + "6"); // Cyan on cyan
text = text.replace(/@[xX]34/g, "\1n\1r\1" + "6"); // Red on cyan
text = text.replace(/@[xX]35/g, "\1n\1m\1" + "6"); // Magenta on cyan
text = text.replace(/@[xX]36/g, "\1n\1y\1" + "6"); // Yellow/brown on cyan
text = text.replace(/@[xX]37/g, "\1n\1w\1" + "6"); // White on cyan
text = text.replace(/@[xX]38/g, "\1h\1k\1" + "6"); // Bright black on cyan
text = text.replace(/@[xX]39/g, "\1h\1b\1" + "6"); // Bright blue on cyan
text = text.replace(/@[xX]3[Aa]/g, "\1h\1g\1" + "6"); // Bright green on cyan
text = text.replace(/@[xX]3[Bb]/g, "\1h\1c\1" + "6"); // Bright cyan on cyan
text = text.replace(/@[xX]3[Cc]/g, "\1h\1r\1" + "6"); // Bright red on cyan
text = text.replace(/@[xX]3[Dd]/g, "\1h\1m\1" + "6"); // Bright magenta on cyan
text = text.replace(/@[xX]3[Ee]/g, "\1h\1y\1" + "6"); // Bright yellow on cyan
text = text.replace(/@[xX]3[Ff]/g, "\1h\1w\1" + "6"); // Bright white on cyan
// Red background
text = text.replace(/@[xX]40/g, "\1n\1k\1" + "1"); // Black on red
text = text.replace(/@[xX]41/g, "\1n\1b\1" + "1"); // Blue on red
text = text.replace(/@[xX]42/g, "\1n\1g\1" + "1"); // Green on red
text = text.replace(/@[xX]43/g, "\1n\1c\1" + "1"); // Cyan on red
text = text.replace(/@[xX]44/g, "\1n\1r\1" + "1"); // Red on red
text = text.replace(/@[xX]45/g, "\1n\1m\1" + "1"); // Magenta on red
text = text.replace(/@[xX]46/g, "\1n\1y\1" + "1"); // Yellow/brown on red
text = text.replace(/@[xX]47/g, "\1n\1w\1" + "1"); // White on red
text = text.replace(/@[xX]48/g, "\1h\1k\1" + "1"); // Bright black on red
text = text.replace(/@[xX]49/g, "\1h\1b\1" + "1"); // Bright blue on red
text = text.replace(/@[xX]4[Aa]/g, "\1h\1g\1" + "1"); // Bright green on red
text = text.replace(/@[xX]4[Bb]/g, "\1h\1c\1" + "1"); // Bright cyan on red
text = text.replace(/@[xX]4[Cc]/g, "\1h\1r\1" + "1"); // Bright red on red
text = text.replace(/@[xX]4[Dd]/g, "\1h\1m\1" + "1"); // Bright magenta on red
text = text.replace(/@[xX]4[Ee]/g, "\1h\1y\1" + "1"); // Bright yellow on red
text = text.replace(/@[xX]4[Ff]/g, "\1h\1w\1" + "1"); // Bright white on red
// Magenta background
text = text.replace(/@[xX]50/g, "\1n\1k\1" + "5"); // Black on magenta
text = text.replace(/@[xX]51/g, "\1n\1b\1" + "5"); // Blue on magenta
text = text.replace(/@[xX]52/g, "\1n\1g\1" + "5"); // Green on magenta
text = text.replace(/@[xX]53/g, "\1n\1c\1" + "5"); // Cyan on magenta
text = text.replace(/@[xX]54/g, "\1n\1r\1" + "5"); // Red on magenta
text = text.replace(/@[xX]55/g, "\1n\1m\1" + "5"); // Magenta on magenta
text = text.replace(/@[xX]56/g, "\1n\1y\1" + "5"); // Yellow/brown on magenta
text = text.replace(/@[xX]57/g, "\1n\1w\1" + "5"); // White on magenta
text = text.replace(/@[xX]58/g, "\1h\1k\1" + "5"); // Bright black on magenta
text = text.replace(/@[xX]59/g, "\1h\1b\1" + "5"); // Bright blue on magenta
text = text.replace(/@[xX]5[Aa]/g, "\1h\1g\1" + "5"); // Bright green on magenta
text = text.replace(/@[xX]5[Bb]/g, "\1h\1c\1" + "5"); // Bright cyan on magenta
text = text.replace(/@[xX]5[Cc]/g, "\1h\1r\1" + "5"); // Bright red on magenta
text = text.replace(/@[xX]5[Dd]/g, "\1h\1m\1" + "5"); // Bright magenta on magenta
text = text.replace(/@[xX]5[Ee]/g, "\1h\1y\1" + "5"); // Bright yellow on magenta
text = text.replace(/@[xX]5[Ff]/g, "\1h\1w\1" + "5"); // Bright white on magenta
// Brown background
text = text.replace(/@[xX]60/g, "\1n\1k\1" + "3"); // Black on brown
text = text.replace(/@[xX]61/g, "\1n\1b\1" + "3"); // Blue on brown
text = text.replace(/@[xX]62/g, "\1n\1g\1" + "3"); // Green on brown
text = text.replace(/@[xX]63/g, "\1n\1c\1" + "3"); // Cyan on brown
text = text.replace(/@[xX]64/g, "\1n\1r\1" + "3"); // Red on brown
text = text.replace(/@[xX]65/g, "\1n\1m\1" + "3"); // Magenta on brown
text = text.replace(/@[xX]66/g, "\1n\1y\1" + "3"); // Yellow/brown on brown
text = text.replace(/@[xX]67/g, "\1n\1w\1" + "3"); // White on brown
text = text.replace(/@[xX]68/g, "\1h\1k\1" + "3"); // Bright black on brown
text = text.replace(/@[xX]69/g, "\1h\1b\1" + "3"); // Bright blue on brown
text = text.replace(/@[xX]6[Aa]/g, "\1h\1g\1" + "3"); // Bright breen on brown
text = text.replace(/@[xX]6[Bb]/g, "\1h\1c\1" + "3"); // Bright cyan on brown
text = text.replace(/@[xX]6[Cc]/g, "\1h\1r\1" + "3"); // Bright red on brown
text = text.replace(/@[xX]6[Dd]/g, "\1h\1m\1" + "3"); // Bright magenta on brown
text = text.replace(/@[xX]6[Ee]/g, "\1h\1y\1" + "3"); // Bright yellow on brown
text = text.replace(/@[xX]6[Ff]/g, "\1h\1w\1" + "3"); // Bright white on brown
// White background
text = text.replace(/@[xX]70/g, "\1n\1k\1" + "7"); // Black on white
text = text.replace(/@[xX]71/g, "\1n\1b\1" + "7"); // Blue on white
text = text.replace(/@[xX]72/g, "\1n\1g\1" + "7"); // Green on white
text = text.replace(/@[xX]73/g, "\1n\1c\1" + "7"); // Cyan on white
text = text.replace(/@[xX]74/g, "\1n\1r\1" + "7"); // Red on white
text = text.replace(/@[xX]75/g, "\1n\1m\1" + "7"); // Magenta on white
text = text.replace(/@[xX]76/g, "\1n\1y\1" + "7"); // Yellow/brown on white
text = text.replace(/@[xX]77/g, "\1n\1w\1" + "7"); // White on white
text = text.replace(/@[xX]78/g, "\1h\1k\1" + "7"); // Bright black on white
text = text.replace(/@[xX]79/g, "\1h\1b\1" + "7"); // Bright blue on white
text = text.replace(/@[xX]7[Aa]/g, "\1h\1g\1" + "7"); // Bright green on white
text = text.replace(/@[xX]7[Bb]/g, "\1h\1c\1" + "7"); // Bright cyan on white
text = text.replace(/@[xX]7[Cc]/g, "\1h\1r\1" + "7"); // Bright red on white
text = text.replace(/@[xX]7[Dd]/g, "\1h\1m\1" + "7"); // Bright magenta on white
text = text.replace(/@[xX]7[Ee]/g, "\1h\1y\1" + "7"); // Bright yellow on white
text = text.replace(/@[xX]7[Ff]/g, "\1h\1w\1" + "7"); // Bright white on white
// Black background, blinking foreground
text = text.replace(/@[xX]80/g, "\1n\1k\1" + "0\1i"); // Blinking black on black
text = text.replace(/@[xX]81/g, "\1n\1b\1" + "0\1i"); // Blinking blue on black
text = text.replace(/@[xX]82/g, "\1n\1g\1" + "0\1i"); // Blinking green on black
text = text.replace(/@[xX]83/g, "\1n\1c\1" + "0\1i"); // Blinking cyan on black
text = text.replace(/@[xX]84/g, "\1n\1r\1" + "0\1i"); // Blinking red on black
text = text.replace(/@[xX]85/g, "\1n\1m\1" + "0\1i"); // Blinking magenta on black
text = text.replace(/@[xX]86/g, "\1n\1y\1" + "0\1i"); // Blinking yellow/brown on black
text = text.replace(/@[xX]87/g, "\1n\1w\1" + "0\1i"); // Blinking white on black
text = text.replace(/@[xX]88/g, "\1h\1k\1" + "0\1i"); // Blinking bright black on black
text = text.replace(/@[xX]89/g, "\1h\1b\1" + "0\1i"); // Blinking bright blue on black
text = text.replace(/@[xX]8[Aa]/g, "\1h\1g\1" + "0\1i"); // Blinking bright green on black
text = text.replace(/@[xX]8[Bb]/g, "\1h\1c\1" + "0\1i"); // Blinking bright cyan on black
text = text.replace(/@[xX]8[Cc]/g, "\1h\1r\1" + "0\1i"); // Blinking bright red on black
text = text.replace(/@[xX]8[Dd]/g, "\1h\1m\1" + "0\1i"); // Blinking bright magenta on black
text = text.replace(/@[xX]8[Ee]/g, "\1h\1y\1" + "0\1i"); // Blinking bright yellow on black
text = text.replace(/@[xX]8[Ff]/g, "\1h\1w\1" + "0\1i"); // Blinking bright white on black
// Blue background, blinking foreground
text = text.replace(/@[xX]90/g, "\1n\1k\1" + "4\1i"); // Blinking black on blue
text = text.replace(/@[xX]91/g, "\1n\1b\1" + "4\1i"); // Blinking blue on blue
text = text.replace(/@[xX]92/g, "\1n\1g\1" + "4\1i"); // Blinking green on blue
text = text.replace(/@[xX]93/g, "\1n\1c\1" + "4\1i"); // Blinking cyan on blue
text = text.replace(/@[xX]94/g, "\1n\1r\1" + "4\1i"); // Blinking red on blue
text = text.replace(/@[xX]95/g, "\1n\1m\1" + "4\1i"); // Blinking magenta on blue
text = text.replace(/@[xX]96/g, "\1n\1y\1" + "4\1i"); // Blinking yellow/brown on blue
text = text.replace(/@[xX]97/g, "\1n\1w\1" + "4\1i"); // Blinking white on blue
text = text.replace(/@[xX]98/g, "\1h\1k\1" + "4\1i"); // Blinking bright black on blue
text = text.replace(/@[xX]99/g, "\1h\1b\1" + "4\1i"); // Blinking bright blue on blue
text = text.replace(/@[xX]9[Aa]/g, "\1h\1g\1" + "4\1i"); // Blinking bright green on blue
text = text.replace(/@[xX]9[Bb]/g, "\1h\1c\1" + "4\1i"); // Blinking bright cyan on blue
text = text.replace(/@[xX]9[Cc]/g, "\1h\1r\1" + "4\1i"); // Blinking bright red on blue
text = text.replace(/@[xX]9[Dd]/g, "\1h\1m\1" + "4\1i"); // Blinking bright magenta on blue
text = text.replace(/@[xX]9[Ee]/g, "\1h\1y\1" + "4\1i"); // Blinking bright yellow on blue
text = text.replace(/@[xX]9[Ff]/g, "\1h\1w\1" + "4\1i"); // Blinking bright white on blue
// Green background, blinking foreground
text = text.replace(/@[xX][Aa]0/g, "\1n\1k\1" + "2\1i"); // Blinking black on green
text = text.replace(/@[xX][Aa]1/g, "\1n\1b\1" + "2\1i"); // Blinking blue on green
text = text.replace(/@[xX][Aa]2/g, "\1n\1g\1" + "2\1i"); // Blinking green on green
text = text.replace(/@[xX][Aa]3/g, "\1n\1c\1" + "2\1i"); // Blinking cyan on green
text = text.replace(/@[xX][Aa]4/g, "\1n\1r\1" + "2\1i"); // Blinking red on green
text = text.replace(/@[xX][Aa]5/g, "\1n\1m\1" + "2\1i"); // Blinking magenta on green
text = text.replace(/@[xX][Aa]6/g, "\1n\1y\1" + "2\1i"); // Blinking yellow/brown on green
text = text.replace(/@[xX][Aa]7/g, "\1n\1w\1" + "2\1i"); // Blinking white on green
text = text.replace(/@[xX][Aa]8/g, "\1h\1k\1" + "2\1i"); // Blinking bright black on green
text = text.replace(/@[xX][Aa]9/g, "\1h\1b\1" + "2\1i"); // Blinking bright blue on green
text = text.replace(/@[xX][Aa][Aa]/g, "\1h\1g\1" + "2\1i"); // Blinking bright green on green
text = text.replace(/@[xX][Aa][Bb]/g, "\1h\1c\1" + "2\1i"); // Blinking bright cyan on green
text = text.replace(/@[xX][Aa][Cc]/g, "\1h\1r\1" + "2\1i"); // Blinking bright red on green
text = text.replace(/@[xX][Aa][Dd]/g, "\1h\1m\1" + "2\1i"); // Blinking bright magenta on green
text = text.replace(/@[xX][Aa][Ee]/g, "\1h\1y\1" + "2\1i"); // Blinking bright yellow on green
text = text.replace(/@[xX][Aa][Ff]/g, "\1h\1w\1" + "2\1i"); // Blinking bright white on green
// Cyan background, blinking foreground
text = text.replace(/@[xX][Bb]0/g, "\1n\1k\1" + "6\1i"); // Blinking black on cyan
text = text.replace(/@[xX][Bb]1/g, "\1n\1b\1" + "6\1i"); // Blinking blue on cyan
text = text.replace(/@[xX][Bb]2/g, "\1n\1g\1" + "6\1i"); // Blinking green on cyan
text = text.replace(/@[xX][Bb]3/g, "\1n\1c\1" + "6\1i"); // Blinking cyan on cyan
text = text.replace(/@[xX][Bb]4/g, "\1n\1r\1" + "6\1i"); // Blinking red on cyan
text = text.replace(/@[xX][Bb]5/g, "\1n\1m\1" + "6\1i"); // Blinking magenta on cyan
text = text.replace(/@[xX][Bb]6/g, "\1n\1y\1" + "6\1i"); // Blinking yellow/brown on cyan
text = text.replace(/@[xX][Bb]7/g, "\1n\1w\1" + "6\1i"); // Blinking white on cyan
text = text.replace(/@[xX][Bb]8/g, "\1h\1k\1" + "6\1i"); // Blinking bright black on cyan
text = text.replace(/@[xX][Bb]9/g, "\1h\1b\1" + "6\1i"); // Blinking bright blue on cyan
text = text.replace(/@[xX][Bb][Aa]/g, "\1h\1g\1" + "6\1i"); // Blinking bright green on cyan
text = text.replace(/@[xX][Bb][Bb]/g, "\1h\1c\1" + "6\1i"); // Blinking bright cyan on cyan
text = text.replace(/@[xX][Bb][Cc]/g, "\1h\1r\1" + "6\1i"); // Blinking bright red on cyan
text = text.replace(/@[xX][Bb][Dd]/g, "\1h\1m\1" + "6\1i"); // Blinking bright magenta on cyan
text = text.replace(/@[xX][Bb][Ee]/g, "\1h\1y\1" + "6\1i"); // Blinking bright yellow on cyan
text = text.replace(/@[xX][Bb][Ff]/g, "\1h\1w\1" + "6\1i"); // Blinking bright white on cyan
// Red background, blinking foreground
text = text.replace(/@[xX][Cc]0/g, "\1n\1k\1" + "1\1i"); // Blinking black on red
text = text.replace(/@[xX][Cc]1/g, "\1n\1b\1" + "1\1i"); // Blinking blue on red
text = text.replace(/@[xX][Cc]2/g, "\1n\1g\1" + "1\1i"); // Blinking green on red
text = text.replace(/@[xX][Cc]3/g, "\1n\1c\1" + "1\1i"); // Blinking cyan on red
text = text.replace(/@[xX][Cc]4/g, "\1n\1r\1" + "1\1i"); // Blinking red on red
text = text.replace(/@[xX][Cc]5/g, "\1n\1m\1" + "1\1i"); // Blinking magenta on red
text = text.replace(/@[xX][Cc]6/g, "\1n\1y\1" + "1\1i"); // Blinking yellow/brown on red
text = text.replace(/@[xX][Cc]7/g, "\1n\1w\1" + "1\1i"); // Blinking white on red
text = text.replace(/@[xX][Cc]8/g, "\1h\1k\1" + "1\1i"); // Blinking bright black on red
text = text.replace(/@[xX][Cc]9/g, "\1h\1b\1" + "1\1i"); // Blinking bright blue on red
text = text.replace(/@[xX][Cc][Aa]/g, "\1h\1g\1" + "1\1i"); // Blinking bright green on red
text = text.replace(/@[xX][Cc][Bb]/g, "\1h\1c\1" + "1\1i"); // Blinking bright cyan on red
text = text.replace(/@[xX][Cc][Cc]/g, "\1h\1r\1" + "1\1i"); // Blinking bright red on red
text = text.replace(/@[xX][Cc][Dd]/g, "\1h\1m\1" + "1\1i"); // Blinking bright magenta on red
text = text.replace(/@[xX][Cc][Ee]/g, "\1h\1y\1" + "1\1i"); // Blinking bright yellow on red
text = text.replace(/@[xX][Cc][Ff]/g, "\1h\1w\1" + "1\1i"); // Blinking bright white on red
// Magenta background, blinking foreground
text = text.replace(/@[xX][Dd]0/g, "\1n\1k\1" + "5\1i"); // Blinking black on magenta
text = text.replace(/@[xX][Dd]1/g, "\1n\1b\1" + "5\1i"); // Blinking blue on magenta
text = text.replace(/@[xX][Dd]2/g, "\1n\1g\1" + "5\1i"); // Blinking green on magenta
text = text.replace(/@[xX][Dd]3/g, "\1n\1c\1" + "5\1i"); // Blinking cyan on magenta
text = text.replace(/@[xX][Dd]4/g, "\1n\1r\1" + "5\1i"); // Blinking red on magenta
text = text.replace(/@[xX][Dd]5/g, "\1n\1m\1" + "5\1i"); // Blinking magenta on magenta
text = text.replace(/@[xX][Dd]6/g, "\1n\1y\1" + "5\1i"); // Blinking yellow/brown on magenta
text = text.replace(/@[xX][Dd]7/g, "\1n\1w\1" + "5\1i"); // Blinking white on magenta
text = text.replace(/@[xX][Dd]8/g, "\1h\1k\1" + "5\1i"); // Blinking bright black on magenta
text = text.replace(/@[xX][Dd]9/g, "\1h\1b\1" + "5\1i"); // Blinking bright blue on magenta
text = text.replace(/@[xX][Dd][Aa]/g, "\1h\1g\1" + "5\1i"); // Blinking bright green on magenta
text = text.replace(/@[xX][Dd][Bb]/g, "\1h\1c\1" + "5\1i"); // Blinking bright cyan on magenta
text = text.replace(/@[xX][Dd][Cc]/g, "\1h\1r\1" + "5\1i"); // Blinking bright red on magenta
text = text.replace(/@[xX][Dd][Dd]/g, "\1h\1m\1" + "5\1i"); // Blinking bright magenta on magenta
text = text.replace(/@[xX][Dd][Ee]/g, "\1h\1y\1" + "5\1i"); // Blinking bright yellow on magenta
text = text.replace(/@[xX][Dd][Ff]/g, "\1h\1w\1" + "5\1i"); // Blinking bright white on magenta
// Brown background, blinking foreground
text = text.replace(/@[xX][Ee]0/g, "\1n\1k\1" + "3\1i"); // Blinking black on brown