Newer
Older
18001
18002
18003
18004
18005
18006
18007
18008
18009
18010
18011
18012
18013
18014
18015
18016
18017
18018
else
{
if ((system.settings & SYS_USRVDELM) == 0)
return false;
}
}
// The message voting and poll variables were added in sbbsdefs.js for
// Synchronet 3.17. Make sure they're defined before referencing them.
if (typeof(MSG_UPVOTE) != "undefined")
{
if ((pMsgHdr.attr & MSG_UPVOTE) == MSG_UPVOTE)
return false;
}
if (typeof(MSG_DOWNVOTE) != "undefined")
{
if ((pMsgHdr.attr & MSG_DOWNVOTE) == MSG_DOWNVOTE)
return false;
}
// Don't include polls as being unreadable messages - They just need to have
// their answer selections read from the header instead of the message body
/*
if (typeof(MSG_POLL) != "undefined")
{
if ((pMsgHdr.attr & MSG_POLL) == MSG_POLL)
return false;
}
*/
return true;
}
// Returns the number of readable messages in a sub-board.
//
// Parameters:
// pMsgbase: The MsgBase object representing the sub-board
// pSubBoardCode: The internal code of the sub-board
//
// Return value: The number of readable messages in the sub-board
function numReadableMsgs(pMsgbase, pSubBoardCode)
{
if ((pMsgbase === null) || !pMsgbase.is_open)
return 0;
var numMsgs = 0;
if (typeof(pMsgbase.get_all_msg_headers) === "function")
18045
18046
18047
18048
18049
18050
18051
18052
18053
18054
18055
18056
18057
18058
18059
18060
18061
18062
18063
18064
18065
18066
18067
18068
18069
{
var msgHdrs = pMsgbase.get_all_msg_headers(true);
for (var msgHdrsProp in msgHdrs)
{
if (msgHdrs[msgHdrsProp] == null)
continue;
else if (isReadableMsgHdr(msgHdrs[msgHdrsProp], pSubBoardCode))
++numMsgs;
}
}
else
{
var msgHeader;
for (var i = 0; i < pMsgbase.total_msgs; ++i)
{
msgHeader = msgBase.get_msg_header(true, i, false);
if (msgHeader == null)
continue;
else if (isReadableMsgHdr(msgHeader, pSubBoardCode))
++numMsgs;
}
}
return numMsgs;
}

nightfox
committed
// Deletes vote messages (messages that have voting response data for a message with
// a given message number).
//
// Parameters:
// pMsgbase: A MessageBase object containing the messages to be deleted
// pMsgNum: The number of the message for which vote messages should be deleted
// pMsgID: The ID of the message for which vote messages should be deleted

nightfox
committed
// pIsMailSub: Boolean - Whether or not it's the personal email area
//
// Return value: An object containing the following properties:
// numVoteMsgs: The number of vote messages for the given message number
// numVoteMsgsDeleted: The number of vote messages that were deleted
// allVoteMsgsDeleted: Boolean - Whether or not all vote messages were deleted
function deleteVoteMsgs(pMsgbase, pMsgNum, pMsgID, pIsEmailSub)

nightfox
committed
18084
18085
18086
18087
18088
18089
18090
18091
18092
18093
18094
18095
18096
18097
18098
18099
18100
18101
18102
18103
18104
18105
18106
18107
{
var retObj = {
numVoteMsgs: 0,
numVoteMsgsDeleted: 0,
allVoteMsgsDeleted: true
};
if ((pMsgbase === null) || !pMsgbase.is_open)
return retObj;
if (typeof(pMsgNum) != "number")
return retObj;
if (pIsEmailSub)
return retObj;
// This relies on get_all_msg_headers() returning vote messages. The get_all_msg_headers()
// function was added in Synchronet 3.16, and the 'true' parameter to get vote headers was
// added in Synchronet 3.17.
if (typeof(pMsgbase.get_all_msg_headers) === "function")
{
var msgHdrs = pMsgbase.get_all_msg_headers(true);
for (var msgHdrsProp in msgHdrs)
{
if (msgHdrs[msgHdrsProp] == null)
continue;
// If this header is a vote header and its thread_back or reply_id matches the given message,
// then we can delete this message.

nightfox
committed
var isVoteMsg = (((msgHdrs[msgHdrsProp].attr & MSG_VOTE) == MSG_VOTE) || ((msgHdrs[msgHdrsProp].attr & MSG_UPVOTE) == MSG_UPVOTE) || ((msgHdrs[msgHdrsProp].attr & MSG_DOWNVOTE) == MSG_DOWNVOTE));
if (isVoteMsg && (msgHdrs[msgHdrsProp].thread_back == pMsgNum) || (msgHdrs[msgHdrsProp].reply_id == pMsgID))

nightfox
committed
{
++retObj.numVoteMsgs;
msgWasDeleted = pMsgbase.remove_msg(false, msgHdrs[msgHdrsProp].number);
retObj.allVoteMsgsDeleted = (retObj.allVoteMsgsDeleted && msgWasDeleted);
if (msgWasDeleted)
++retObj.numVoteMsgsDeleted;
}
}
}
return retObj;
}
/////////////////////////////////////////////////////////////////////////
18126
18127
18128
18129
18130
18131
18132
18133
18134
18135
18136
18137
18138
18139
18140
18141
18142
18143
18144
18145
18146
18147
18148
18149
18150
// Debug helper & error output functions
// Prints information from a message header on the screen, for debugging purpurposes.
//
// Parameters:
// pMsgHdr: A message header object
function printMsgHdr(pMsgHdr)
{
for (var prop in pMsgHdr)
{
if ((prop == "field_list") && (typeof(pMsgHdr[prop]) == "object"))
{
console.print(prop + ":\r\n");
for (var objI = 0; objI < pMsgHdr[prop].length; ++objI)
{
console.print(" " + objI + ":\r\n");
for (var innerProp in pMsgHdr[prop][objI])
console.print(" " + innerProp + ": " + pMsgHdr[prop][objI][innerProp] + "\r\n");
}
}
else
console.print(prop + ": " + pMsgHdr[prop] + "\r\n");
}
console.pause();
}
// Closes a poll, using an existing MessageBase object.
//
// Parameters:
// pMsgbase: A MessageBase object representing the current sub-board. It
// must be open.
// pMsgNum: The message number (not the index)
//
// Return value: Boolean - Whether or not closing the poll succeeded
function closePollWithOpenMsgbase(pMsgbase, pMsgNum)
{
var pollClosed = false;
if ((pMsgbase !== null) && pMsgbase.is_open)
{

nightfox
committed
var userNameOrAlias = user.alias;
// See if the poll was posted using the user's real name instead of
// their alias
var msgHdr = pMsgbase.get_msg_header(false, pMsgNum, false);
if ((msgHdr != null) && ((msgHdr.attr & MSG_POLL) == MSG_POLL))
{

nightfox
committed
if (msgHdr.from.toUpperCase() == user.name.toUpperCase())
userNameOrAlias = msgHdr.from;
}

nightfox
committed
// Close the poll (the close_poll() method was added in the Synchronet
// 3.17 build on August 19, 2017)
pollClosed = pMsgbase.close_poll(pMsgNum, userNameOrAlias);
18177
18178
18179
18180
18181
18182
18183
18184
18185
18186
18187
18188
18189
18190
18191
18192
18193
18194
18195
18196
18197
18198
18199
}
return pollClosed;
}
// Closes a poll.
//
// Parameters:
// pSubBoardCode: The internal code of the sub-board
// pMsgNum: The message number (not the index)
//
// Return value: Boolean - Whether or not closing the poll succeeded
function closePoll(pSubBoardCode, pMsgNum)
{
var pollClosed = false;
var msgbase = new MsgBase(pSubBoardCode);
if (msgbase.open())
{
pollClosed = closePollWithOpenMsgbase(msgbase, pMsgNum);
msgbase.close();
}
return pollClosed;
}
18200
18201
18202
18203
18204
18205
18206
18207
18208
18209
18210
18211
18212
18213
18214
18215
18216
18217
18218
18219
18220
18221
18222
18223
18224
18225
18226
18227
18228
// Gets a message header from the messagebase, either by index (offset) or number.
//
// Parameters:
// pMsgbase: Optional messagebase object. If this is provided, then pSubBoardCode is not used.
// pSubBoardCode: The messagebase sub-board code
// pByIdx: Boolean - Whether or not to get the message header by index (if false, then by number)
// pMsgIdxOrNum: The message index or number of the message header to retrieve
// pExpandFields: Boolean - Whether or not to expand fields for the message header
function getHdrFromMsgbase(pMsgbase, pSubBoardCode, pByIdx, pMsgIdxOrNum, pExpandFields)
{
var msgbaseIsOpen = false;
var msgbase = null;
var msgHdr = null;
if (pMsgbase == null)
{
msgbase = new MsgBase(pSubBoardCode);
msgbaseIsOpen = msgbase.open();
}
else
{
msgbase = pMsgbase;
msgbaseIsOpen = pMsgbase.is_open;
}
if (msgbaseIsOpen)
{
var getMsgHdr = true;
if (pByIdx)
getMsgHdr = ((pMsgIdxOrNum >= 0) && (pMsgIdxOrNum < msgbase.total_msgs))
if (getMsgHdr)

Eric Oulashin
committed
msgHdr = msgbase.get_msg_header(pByIdx, pMsgIdxOrNum, pExpandFields, true); // Last true: Include votes
if (pMsgbase == null)
msgbase.close();
}
return msgHdr;
}
18236
18237
18238
18239
18240
18241
18242
18243
18244
18245
18246
18247
18248
18249
18250
18251
18252
18253
18254
18255
18256
18257
18258
18259
18260
18261
18262
18263
18264
18265
18266
18267
18268
18269
18270
18271
18272
18273
18274
18275
18276
18277
18278
18279
18280
18281
18282
18283
18284
18285
18286
18287
18288
18289
18290
18291
18292
18293
18294
18295
18296
18297
18298
18299
18300
18301
18302
18303
18304
18305
18306
18307
18308
18309
18310
18311
18312
18313
18314
18315
18316
18317
18318
18319
18320
// Inputs a string from the user, restricting their input to certain keys (optionally).
//
// Parameters:
// pKeys: A string containing valid characters for input. Optional
// pMaxNumChars: The maximum number of characters to input. Optional
// pCaseSensitive: Boolean - Whether or not the input should be case-sensitive. Optional.
// Defaults to true. If false, then the user input will be uppercased.
//
// Return value: A string containing the user's input
function consoleGetStrWithValidKeys(pKeys, pMaxNumChars, pCaseSensitive)
{
var maxNumChars = 0;
if ((typeof(pMaxNumChars) == "number") && (pMaxNumChars > 0))
maxNumChars = pMaxNumChars;
var regexPattern = (typeof(pKeys) == "string" ? "[" + pKeys + "]" : ".");
var caseSensitive = (typeof(pCaseSensitive) == "boolean" ? pCaseSensitive : true);
var regex = new RegExp(regexPattern, (caseSensitive ? "" : "i"));
var CTRL_H = "\x08";
var BACKSPACE = CTRL_H;
var CTRL_M = "\x0d";
var KEY_ENTER = CTRL_M;
var modeBits = (caseSensitive ? K_NONE : K_UPPER);
var userInput = "";
var continueOn = true;
while (continueOn)
{
var userChar = console.getkey(K_NOECHO|modeBits);
if (regex.test(userChar) && isPrintableChar(userChar))
{
var appendChar = true;
if ((maxNumChars > 0) && (userInput.length >= maxNumChars))
appendChar = false;
if (appendChar)
{
userInput += userChar;
if ((modeBits & K_NOECHO) == 0)
console.print(userChar);
}
}
else if (userChar == BACKSPACE)
{
if (userInput.length > 0)
{
if ((modeBits & K_NOECHO) == 0)
{
console.print(BACKSPACE);
console.print(" ");
console.print(BACKSPACE);
}
userInput = userInput.substr(0, userInput.length-1);
}
}
else if (userChar == KEY_ENTER)
{
continueOn = false;
if ((modeBits & K_NOCRLF) == 0)
console.crlf();
}
}
return userInput;
}
// Returns whether or not a character is printable.
//
// Parameters:
// pChar: A character to test
//
// Return value: Boolean - Whether or not the character is printable
function isPrintableChar(pChar)
{
// Make sure pChar is valid and is a string.
if (typeof(pChar) != "string")
return false;
if (pChar.length == 0)
return false;
// Make sure the character is a printable ASCII character in the range of 32 to 254,
// except for 127 (delete).
var charCode = pChar.charCodeAt(0);
return ((charCode > 31) && (charCode < 255) && (charCode != 127));
}
// Adds message attributes to a message header and saves it in the messagebase.
// To do that, this function first loads the messag header from the messagebase
// without expanded fields, applies the attributes, and then saves the header
// back to the messagebase.
//
// Parameters:
// pMsgbaseOrSubCode: An open MessageBase object or a sub-board code (string)
// pMsgNum: The number of the message to update
// pMsgAttrs: The message attributes to apply to the message (numeric bitfield)
//
// Return value: An object containing the following properties:
// saveSucceeded: Boolean - Whether or not the message header was successfully saved
// msgAttrs: A numeric bitfield containing the updated attributes of the message header
function applyAttrsInMsgHdrInMessagbase(pMsgbaseOrSubCode, pMsgNum, pMsgAttrs)
{
var retObj = {
saveSucceeded: false,
msgAttrs: 0
};
var msgbaseOpen = false;
var msgbase = null;
if (typeof(pMsgbaseOrSubCode) == "object")
{
msgbase = pMsgbaseOrSubCode;
msgbaseOpen = msgbase.is_open;
}
else if (typeof(pMsgbaseOrSubCode) == "string")
{
msgbase = new MsgBase(pMsgbaseOrSubCode);
msgbaseOpen = msgbase.open();
}
else
return retObj;
if (msgbaseOpen)
{
// Get the message header without expanded fields (we can't save it with
// expanded fields), then add the 'read' attribute and save it back to the messagebase.
var msgHdr = msgbase.get_msg_header(false, pMsgNum, false);
if (msgHdr != null)
{
msgHdr.attr |= pMsgAttrs;
// TODO: Occasional when going to next message area:
// Error: Error -110 adding SENDERNETADDR field to message header
retObj.saveSucceeded = msgbase.put_msg_header(false, pMsgNum, msgHdr);
if (retObj.saveSucceeded)
retObj.msgAttrs = msgHdr.attr;
else
{
writeToSysAndNodeLog("Failed to save message header with the following attributes: " + msgAttrsToString(pMsgAttrs), LOG_ERR);
writeToSysAndNodeLog(getMsgAreaDescStr(msgbase), LOG_ERR);
writeToSysAndNodeLog(format("Message offset: %d, number: %d", msgHdr.offset, msgHdr.number), LOG_ERR);
writeToSysAndNodeLog("Status: " + msgbase.status, LOG_ERR);
writeToSysAndNodeLog("Error: " + msgbase.error, LOG_ERR);
/*
// For sysops, output a debug message
Eric Oulashin
committed
if (user.is_sysop)
18379
18380
18381
18382
18383
18384
18385
18386
18387
18388
18389
18390
18391
18392
18393
18394
18395
18396
18397
18398
18399
18400
18401
{
console.print("\1n");
console.crlf();
console.print("* Failed to save msg header the with the following attributes: " + msgAttrsToString(pMsgAttrs));
console.crlf();
console.print("Status: " + msgbase.status);
console.crlf();
console.print("Error: " + msgbase.error);
console.crlf();
console.crlf();
//console.print("put_msg_header params: false, " + msgHdr.number + ", header:\r\n");
//console.print("put_msg_header params: true, " + msgHdr.offset + ", header:\r\n");
//console.print("put_msg_header params: " + msgHdr.number + ", header:\r\n");
printMsgHdr(msgHdr);
}
*/
}
}
// If a sub-board code was passed in, then close the messagebase object
// that we created here.
if (typeof(pMsgbaseOrSubCode) == "string")
msgbase.close();
}
return retObj;
}
18407
18408
18409
18410
18411
18412
18413
18414
18415
18416
18417
18418
18419
18420
18421
18422
18423
18424
18425
18426
18427
18428
18429
18430
18431
18432
18433
18434
18435
18436
18437
18438
18439
18440
18441
18442
18443
18444
18445
18446
18447
18448
18449
18450
18451
18452
18453
18454
18455
18456
18457
18458
18459
18460
18461
18462
18463
18464
18465
18466
18467
18468
18469
18470
18471
18472
18473
18474
18475
18476
18477
18478
18479
18480
18481
18482
18483
18484
18485
18486
18487
18488
18489
18490
18491
18492
18493
18494
18495
18496
18497
18498
18499
18500
18501
18502
18503
18504
18505
// Converts a message attributes bitfield to a string.
//
// Parameters:
// pMsgAttrs: A numeric type with message attribute bits
//
// Return value: A string containing a list of the message attributes
function msgAttrsToString(pMsgAttrs)
{
if (typeof(pMsgAttrs) != "number")
return "";
var attrsStr = "";
if ((pMsgAttrs & MSG_PRIVATE) == MSG_PRIVATE)
{
if (attrsStr.length > 0)
attrsStr += ", ";
attrsStr += "MSG_PRIVATE";
}
if ((pMsgAttrs & MSG_READ) == MSG_READ)
{
if (attrsStr.length > 0)
attrsStr += ", ";
attrsStr += "MSG_READ";
}
if ((pMsgAttrs & MSG_PERMANENT) == MSG_PERMANENT)
{
if (attrsStr.length > 0)
attrsStr += ", ";
attrsStr += "MSG_PERMANENT";
}
if ((pMsgAttrs & MSG_LOCKED) == MSG_LOCKED)
{
if (attrsStr.length > 0)
attrsStr += ", ";
attrsStr += "MSG_LOCKED";
}
if ((pMsgAttrs & MSG_DELETE) == MSG_DELETE)
{
if (attrsStr.length > 0)
attrsStr += ", ";
attrsStr += "MSG_DELETE";
}
if ((pMsgAttrs & MSG_ANONYMOUS) == MSG_ANONYMOUS)
{
if (attrsStr.length > 0)
attrsStr += ", ";
attrsStr += "MSG_ANONYMOUS";
}
if ((pMsgAttrs & MSG_KILLREAD) == MSG_KILLREAD)
{
if (attrsStr.length > 0)
attrsStr += ", ";
attrsStr += "MSG_KILLREAD";
}
if ((pMsgAttrs & MSG_MODERATED) == MSG_MODERATED)
{
if (attrsStr.length > 0)
attrsStr += ", ";
attrsStr += "MSG_MODERATED";
}
if ((pMsgAttrs & MSG_VALIDATED) == MSG_VALIDATED)
{
if (attrsStr.length > 0)
attrsStr += ", ";
attrsStr += "MSG_VALIDATED";
}
if ((pMsgAttrs & MSG_REPLIED) == MSG_REPLIED)
{
if (attrsStr.length > 0)
attrsStr += ", ";
attrsStr += "MSG_REPLIED";
}
if ((pMsgAttrs & MSG_NOREPLY) == MSG_NOREPLY)
{
if (attrsStr.length > 0)
attrsStr += ", ";
attrsStr += "MSG_NOREPLY";
}
if ((pMsgAttrs & MSG_UPVOTE) == MSG_UPVOTE)
{
if (attrsStr.length > 0)
attrsStr += ", ";
attrsStr += "MSG_UPVOTE";
}
if ((pMsgAttrs & MSG_DOWNVOTE) == MSG_DOWNVOTE)
{
if (attrsStr.length > 0)
attrsStr += ", ";
attrsStr += "MSG_DOWNVOTE";
}
if ((pMsgAttrs & MSG_POLL) == MSG_POLL)
{
if (attrsStr.length > 0)
attrsStr += ", ";
attrsStr += "MSG_POLL";
}
return attrsStr;
}
18506
18507
18508
18509
18510
18511
18512
18513
18514
18515
18516
18517
18518
18519
18520
18521
18522
18523
18524
18525
18526
18527
18528
18529
18530
18531
18532
18533
18534
18535
18536
18537
18538
18539
18540
18541
18542
18543
18544
18545
18546
18547
18548
18549
18550
18551
18552
18553
18554
18555
18556
18557
18558
18559
18560
18561
18562
18563
18564
18565
18566
18567
18568
18569
18570
18571
18572
18573
18574
18575
18576
18577
18578
18579
18580
18581
18582
18583
18584
18585
18586
18587
18588
18589
18590
18591
// Returns the index of the first Synchronet attribute code before a given index
// in a string.
//
// Parameters:
// pStr: The string to search in
// pIdx: The index to search back from
// pSeriesOfAttrs: Optional boolean - Whether or not to look for a series of
// attributes. Defaults to false (look for just one attribute).
// pOnlyInWord: Optional boolean - Whether or not to look only in the current word
// (with words separated by whitespace). Defaults to false.
//
// Return value: The index of the first Synchronet attribute code before the given
// index in the string, or -1 if there is none or if the parameters
// are invalid
function strIdxOfSyncAttrBefore(pStr, pIdx, pSeriesOfAttrs, pOnlyInWord)
{
if (typeof(pStr) != "string")
return -1;
if (typeof(pIdx) != "number")
return -1;
if ((pIdx < 0) || (pIdx >= pStr.length))
return -1;
var seriesOfAttrs = (typeof(pSeriesOfAttrs) == "boolean" ? pSeriesOfAttrs : false);
var onlyInWord = (typeof(pOnlyInWord) == "boolean" ? pOnlyInWord : false);
var attrCodeIdx = pStr.lastIndexOf("\1", pIdx-1);
if (attrCodeIdx > -1)
{
// If we are to only check the current word, then continue only if
// there isn't a space between the attribute code and the given index.
if (onlyInWord)
{
if (pStr.lastIndexOf(" ", pIdx-1) >= attrCodeIdx)
attrCodeIdx = -1;
}
}
if (attrCodeIdx > -1)
{
var syncAttrRegexWholeWord = /^\1[krgybmcw01234567hinpq,;\.dtl<>\[\]asz]$/i;
if (syncAttrRegexWholeWord.test(pStr.substr(attrCodeIdx, 2)))
{
if (seriesOfAttrs)
{
for (var i = attrCodeIdx - 2; i >= 0; i -= 2)
{
if (syncAttrRegexWholeWord.test(pStr.substr(i, 2)))
attrCodeIdx = i;
else
break;
}
}
}
else
attrCodeIdx = -1;
}
return attrCodeIdx;
}
// Returns a string with any Synchronet color/attribute codes found in a string
// before a given index.
//
// Parameters:
// pStr: The string to search in
// pIdx: The index in the string to search before
//
// Return value: A string containing any Synchronet attribute codes found before
// the given index in the given string
function getAttrsBeforeStrIdx(pStr, pIdx)
{
if (typeof(pStr) != "string")
return "";
if (typeof(pIdx) != "number")
return "";
if (pIdx < 0)
return "";
var idx = (pIdx < pStr.length ? pIdx : pStr.length-1);
var attrStartIdx = strIdxOfSyncAttrBefore(pStr, idx, true, false);
var attrEndIdx = strIdxOfSyncAttrBefore(pStr, idx, false, false); // Start of 2-character code
var attrsStr = "";
if ((attrStartIdx > -1) && (attrEndIdx > -1))
attrsStr = pStr.substring(attrStartIdx, attrEndIdx+2);
return attrsStr;
}
// Given a message header, this function gets/calculates the message's
// upvotes, downvotes, and vote score, if that information is present.
//
// Parameters:
// pMsgHdr: A message header object
//
// Return value: An object containign the following properties:
// foundVoteInfo: Boolean - Whether the vote information exited in the header
// upvotes: The number of upvotes
// downvotes: The number of downvotes
// voteScore: The overall vote score

Eric Oulashin
committed
function getMsgUpDownvotesAndScore(pMsgHdr, pVerbose)
{
var retObj = {
foundVoteInfo: false,
upvotes: 0,
downvotes: 0,
voteScore: 0
};
if ((pMsgHdr.hasOwnProperty("total_votes") || pMsgHdr.hasOwnProperty("downvotes")) && pMsgHdr.hasOwnProperty("upvotes"))
{
retObj.foundVoteInfo = true;
retObj.upvotes = pMsgHdr.upvotes;
if (pMsgHdr.hasOwnProperty("downvotes"))
retObj.downvotes = pMsgHdr.downvotes;
else
retObj.downvotes = pMsgHdr.total_votes - pMsgHdr.upvotes;
retObj.voteScore = pMsgHdr.upvotes - retObj.downvotes;

Eric Oulashin
committed
if (pVerbose && user.is_sysop)
{
console.print("\1n\r\n");
console.print("Vote information from header:\r\n");
console.print("Upvotes: " + pMsgHdr.upvotes + "\r\n");
console.print("Downvotes: " + retObj.downvotes + "\r\n");
console.print("Score: " + retObj.voteScore + "\r\n");
console.pause();
}
}
else
{
if (pVerbose && user.is_sysop)
console.print("\1n\r\nMsg header does NOT have needed vote info\r\n\1p");
}
return retObj;
}
// Removes any initial Synchronet attribute(s) from a message body,
// which can sometimes color the whole message.
//
// Parameters:
// pMsgBody: The original message body
//
// Return value: The message body, with any initial color removed
function removeInitialColorFromMsgBody(pMsgBody)
{

Eric Oulashin
committed
if (pMsgBody == null)
return "";
18652
18653
18654
18655
18656
18657
18658
18659
18660
18661
18662
18663
18664
18665
18666
18667
18668
18669
18670
18671
18672
18673
18674
18675
18676
18677
18678
18679
18680
18681
18682
18683
18684
18685
18686
18687
18688
18689
var msgBody = pMsgBody;
msgBodyLines = pMsgBody.split("\r\n", 3);
if (msgBodyLines.length == 3)
{
var onlySyncAttrsRegexWholeWord = /^([krgybmcw01234567hinpq,;\.dtl<>\[\]asz])+$/i;
var line1Match = /^ Re: .*/.test(strip_ctrl(msgBodyLines[0]));
var line2Match = /^ By: .* on .*/.test(strip_ctrl(msgBodyLines[1]));
var line3OnlySyncAttrs = onlySyncAttrsRegexWholeWord.test(msgBodyLines[2]);
if (line1Match && line2Match)
{
msgBodyLines = pMsgBody.split("\r\n");
msgBodyLines[0] = strip_ctrl(msgBodyLines[0]);
msgBodyLines[1] = strip_ctrl(msgBodyLines[1]);
if (line3OnlySyncAttrs)
{
var originalLine3SyncAttrs = msgBodyLines[2];
msgBodyLines[2] = strip_ctrl(msgBodyLines[2]);
// If the first word of the 4th line is only Synchronet attribute codes,
// and they're the same as the codes on the 3rd line, then remove them.
if (msgBodyLines.length >= 4)
{
var line4Words = msgBodyLines[3].split(" ");
if ((line4Words.length > 0) && onlySyncAttrsRegexWholeWord.test(line4Words[0]) && (line4Words[0] == originalLine3SyncAttrs))
msgBodyLines[3] = msgBodyLines[3].substr(line4Words[0].length);
}
}
msgBody = "";
for (var i = 0; i < msgBodyLines.length; ++i)
msgBody += msgBodyLines[i] + "\r\n";
// Remove the trailing \r\n characters from msgBody
msgBody = msgBody.substr(0, msgBody.length-2);
}
}
return msgBody;
}
// Finds a user with a name, alias, or handle matching a given string.
// If system.matchuser() can't find it, this will iterate through all users
// to find the first user with a name, alias, or handle matching the given
// name.
function findUserNumWithName(pName)
{
var userNum = system.matchuser(pName);
if (userNum == 0)
userNum = system.matchuserdata(U_NAME, pName);
if (userNum == 0)
userNum = system.matchuserdata(U_ALIAS, pName);
if (userNum == 0)
userNum = system.matchuserdata(U_HANDLE, pName);
return userNum;
}
18706
18707
18708
18709
18710
18711
18712
18713
18714
18715
18716
18717
18718
18719
18720
18721
18722
18723
18724
18725
18726
18727
18728
18729
18730
18731
18732
18733
18734
18735
18736
18737
18738
18739
18740
18741
18742
18743
18744
18745
18746
18747
18748
18749
18750
18751
18752
18753
18754
18755
18756
18757
18758
18759
18760
18761
18762
18763
18764
18765
18766
18767
18768
18769
18770
18771
18772
18773
18774
18775
18776
18777
18778
18779
18780
18781
18782
18783
18784
18785
18786
18787
18788
18789
18790
18791
18792
18793
18794
18795
18796
18797
18798
18799
18800
18801
18802
18803
18804
18805
18806
18807
18808
18809
18810
18811
18812
18813
18814
18815
18816
18817
18818
18819
18820
18821
18822
18823
18824
18825
18826
18827
18828
18829
18830
18831
18832
18833
18834
18835
18836
18837
18838
18839
18840
18841
18842
18843
18844
18845
18846
18847
18848
18849
18850
18851
18852
18853
18854
18855
18856
18857
18858
18859
18860
18861
18862
18863
18864
18865
18866
18867
18868
18869
18870
18871
18872
18873
18874
18875
18876
18877
18878
18879
18880
18881
18882
18883
18884
18885
18886
18887
18888
18889
18890
18891
// Inputs a string from the user, with a timeout
//
// Parameters:
// pMode: The mode bits to use for the input (i.e., defined in sbbsdefs.js)
// pMaxLength: The maximum length of the string (0 or less for no limit)
// pTimeout: The timeout (in milliseconds). When the timeout is reached,
// input stops and the user's input is returned.
//
// Return value: The user's input (string)
function getStrWithTimeout(pMode, pMaxLength, pTimeout)
{
var inputStr = "";
var mode = K_NONE;
if (typeof(pMode) == "number")
mode = pMode;
var maxWidth = 0;
if (typeof(pMaxLength) == "number")
maxWidth = pMaxLength;
var timeout = 0;
if (typeof(pTimeout) == "number")
timeout = pTimeout;
var setNormalAttrAtEnd = false;
if (((mode & K_LINE) == K_LINE) && (maxWidth > 0) && console.term_supports(USER_ANSI))
{
var curPos = console.getxy();
printf("\1n\1w\1h\1" + "4%" + maxWidth + "s", "");
console.gotoxy(curPos);
setNormalAttrAtEnd = true;
}
var curPos = console.getxy();
var userKey = "";
do
{
userKey = console.inkey(mode, timeout);
if ((userKey.length > 0) && isPrintableChar(userKey))
{
var allowAppendChar = true;
if ((maxWidth > 0) && (inputStr.length >= maxWidth))
allowAppendChar = false;
if (allowAppendChar)
{
inputStr += userKey;
console.print(userKey);
++curPos.x;
}
}
else if (userKey == BACKSPACE)
{
if (inputStr.length > 0)
{
inputStr = inputStr.substr(0, inputStr.length-1);
console.gotoxy(curPos.x-1, curPos.y);
console.print(" ");
console.gotoxy(curPos.x-1, curPos.y);
--curPos.x;
}
}
else if (userKey == KEY_ENTER)
userKey = "";
} while(userKey.length > 0);
if (setNormalAttrAtEnd)
console.print("\1n");
return inputStr;
}
// Calculates the page number (1-based) and top index for the page (0-based),
// given an item index.
//
// Parameters:
// pItemIdx: The index of the item
// pNumItemsPerPage: The number of items per page
//
// Return value: An object containing the following properties:
// pageNum: The page number of the item (1-based; will be 0 if not found)
// pageTopIdx: The index of the top item on the page (or -1 if not found)
function calcPageNumAndTopPageIdx(pItemIdx, pNumItemsPerPage)
{
var retObj = {
pageNum: 0,
pageTopIdx: -1
};
var pageNum = 1;
var topIdx = 0;
var continueOn = true;
do
{
var endIdx = topIdx + pNumItemsPerPage;
if ((pItemIdx >= topIdx) && (pItemIdx < endIdx))
{
continueOn = false;
retObj.pageNum = pageNum;
retObj.pageTopIdx = topIdx;
}
else
{
++pageNum;
topIdx = endIdx;
}
} while (continueOn);
return retObj;
}
// Finds the page number of a message group or sub-board, given some text to
// search for.
//
// Parameters:
// pText: The text to search for in the items
// pNumItemsPerPage: The number of items per page
// pSubBoard: Boolean - If true, search the sub-board list for the given group index.
// If false, search the group list.
// pStartItemIdx: The item index to start at
// pGrpIdx: The index of the group to search in (only for doing a sub-board search)
//
// Return value: An object containing the following properties:
// pageNum: The page number of the item (1-based; will be 0 if not found)
// pageTopIdx: The index of the top item on the page (or -1 if not found)
// itemIdx: The index of the item (or -1 if not found)
function getMsgAreaPageNumFromSearch(pText, pNumItemsPerPage, pSubBoard, pStartItemIdx, pGrpIdx)
{
var retObj = {
pageNum: 0,
pageTopIdx: -1,
itemIdx: -1
};
// Sanity checking
if ((typeof(pText) != "string") || (typeof(pNumItemsPerPage) != "number") || (typeof(pSubBoard) != "boolean"))
return retObj;
// Convert the text to uppercase for case-insensitive searching
var srchText = pText.toUpperCase();
if (pSubBoard)
{
if ((typeof(pGrpIdx) == "number") && (pGrpIdx >= 0) && (pGrpIdx < msg_area.grp_list.length))
{
// Go through the sub-board list of the given group and
// search for text in the descriptions
for (var i = pStartItemIdx; i < msg_area.grp_list[pGrpIdx].sub_list.length; ++i)
{
if ((msg_area.grp_list[pGrpIdx].sub_list[i].description.toUpperCase().indexOf(srchText) > -1) ||
(msg_area.grp_list[pGrpIdx].sub_list[i].name.toUpperCase().indexOf(srchText) > -1))
{
retObj.itemIdx = i;
// Figure out the page number and top index for the page
var pageObj = calcPageNumAndTopPageIdx(i, pNumItemsPerPage);
if ((pageObj.pageNum > 0) && (pageObj.pageTopIdx > -1))
{
retObj.pageNum = pageObj.pageNum;
retObj.pageTopIdx = pageObj.pageTopIdx;
}
break;
}
}
}
}
else
{
// Go through the message group list and look for a match
for (var i = pStartItemIdx; i < msg_area.grp_list.length; ++i)
{
if ((msg_area.grp_list[i].name.toUpperCase().indexOf(srchText) > -1) ||
(msg_area.grp_list[i].description.toUpperCase().indexOf(srchText) > -1))
{
retObj.itemIdx = i;
// Figure out the page number and top index for the page
var pageObj = calcPageNumAndTopPageIdx(i, pNumItemsPerPage);
if ((pageObj.pageNum > 0) && (pageObj.pageTopIdx > -1))
{
retObj.pageNum = pageObj.pageNum;
retObj.pageTopIdx = pageObj.pageTopIdx;
}
break;
}
}
}
return retObj;
}
18892
18893
18894
18895
18896
18897
18898
18899
18900
18901
18902
18903
18904
18905
18906
18907
18908
18909
18910
18911
18912
18913
18914
18915
18916
18917
18918
18919
18920
18921
18922
18923
18924
18925
18926
18927
18928
18929
18930
18931
18932
18933
18934
18935
18936
18937
18938
18939
18940
18941
18942
18943
18944
18945
18946
18947
18948
18949
18950
18951
18952
18953
18954
18955
18956
18957
18958
18959
18960
18961
18962
// Finds a message group index with search text, matching either the name or
// description, case-insensitive.
//
// Parameters:
// pSearchText: The name/description text to look for
// pStartItemIdx: The item index to start at. Defaults to 0
//
// Return value: The index of the message group, or -1 if not found
function findMsgGrpIdxFromText(pSearchText, pStartItemIdx)
{
if (typeof(pSearchText) != "string")
return -1;
var grpIdx = -1;
var startIdx = (typeof(pStartItemIdx) == "number" ? pStartItemIdx : 0);
if ((startIdx < 0) || (startIdx > msg_area.grp_list.length))
startIdx = 0;
// Go through the message group list and look for a match
var searchTextUpper = pSearchText.toUpperCase();
for (var i = startIdx; i < msg_area.grp_list.length; ++i)
{
if ((msg_area.grp_list[i].name.toUpperCase().indexOf(searchTextUpper) > -1) ||
(msg_area.grp_list[i].description.toUpperCase().indexOf(searchTextUpper) > -1))
{
grpIdx = i;
break;
}
}
return grpIdx;
}
// Finds a message group index with search text, matching either the name or
// description, case-insensitive.
//
// Parameters:
// pGrpIdx: The index of the message group
// pSearchText: The name/description text to look for
// pStartItemIdx: The item index to start at. Defaults to 0
//
// Return value: The index of the message group, or -1 if not found
function findSubBoardIdxFromText(pGrpIdx, pSearchText, pStartItemIdx)
{
if (typeof(pGrpIdx) != "number")
return -1;
if (typeof(pSearchText) != "string")
return -1;
var subBoardIdx = -1;
var startIdx = (typeof(pStartItemIdx) == "number" ? pStartItemIdx : 0);
if ((startIdx < 0) || (startIdx > msg_area.grp_list[pGrpIdx].sub_list.length))
startIdx = 0;
// Go through the message group list and look for a match
var searchTextUpper = pSearchText.toUpperCase();
for (var i = startIdx; i < msg_area.grp_list[pGrpIdx].sub_list.length; ++i)
{
if ((msg_area.grp_list[pGrpIdx].sub_list[i].name.toUpperCase().indexOf(searchTextUpper) > -1) ||
(msg_area.grp_list[pGrpIdx].sub_list[i].description.toUpperCase().indexOf(searchTextUpper) > -1))
{
subBoardIdx = i;
break;
}
}
return subBoardIdx;
}
18963
18964
18965
18966
18967
18968
18969
18970
18971
18972
18973
18974
18975
18976
18977
18978
18979
18980
18981
18982
18983
18984
18985
18986
18987
18988
18989
18990
18991
18992
18993
18994
18995
18996
18997
18998
18999
19000
// Searches for a @MSG_TO @-code in a string and inserts a color/attribute code
// before the @-code in the string.
//
// Parameters:
// pStr: The string to look in
// pToUserColor: The color/attribute code to insert before the @MSG_TO @-code
//
// Return value: A string with the given color/attribute code inserted before the
// @MSG_TO @-code
function strWithToUserColor(pStr, pToUserColor)
{
if ((typeof(pStr) != "string") || (typeof(pToUserColor) != "string"))
return "";
if (pToUserColor.length == 0)
return pStr;
// Find start & end indexes of a @MSG_TO* @-code, i.e.,
// @MSG_TO, @MSG_TO_NAME, @MSG_TO_EXT, @MSG_TO_NET
var toCodeStartIdx = pStr.indexOf("@MSG_TO");
if (toCodeStartIdx < 0)
return pStr;
// Insert the color in the right position and return the line
return pStr.substr(0, toCodeStartIdx) + "\1n" + pToUserColor + pStr.substr(toCodeStartIdx) + "\1n";
/*
// Insert the color in the right position, and
// put a \1n right after the end of the @-code
var str = "";
var toCodeEndIdx = pStr.indexOf("@", toCodeStartIdx+1);
if (toCodeEndIdx >= 0)
{
str = pStr.substr(0, toCodeStartIdx) + "\1n" + pToUserColor + pStr.substr(toCodeStartIdx, toCodeEndIdx-toCodeStartIdx+1)
+ "\1n" + pStr.substr(toCodeEndIdx);
}
else
str = pStr.substr(0, toCodeStartIdx) + "\1n" + pToUserColor + pStr.substr(toCodeStartIdx) + "\1n";
return str;
*/
}