Newer
Older
function deleteVoteMsgs(pMsgbase, pMsgNum, pMsgID, pIsEmailSub)

nightfox
committed
19002
19003
19004
19005
19006
19007
19008
19009
19010
19011
19012
19013
19014
19015
19016
19017
19018
19019
19020
19021
19022
19023
19024
19025
{
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;
}
/////////////////////////////////////////////////////////////////////////
19044
19045
19046
19047
19048
19049
19050
19051
19052
19053
19054
19055
19056
19057
19058
19059
19060
19061
19062
19063
19064
19065
19066
19067
19068
// 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);
19095
19096
19097
19098
19099
19100
19101
19102
19103
19104
19105
19106
19107
19108
19109
19110
19111
19112
19113
19114
19115
19116
19117
}
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;
}
19118
19119
19120
19121
19122
19123
19124
19125
19126
19127
19128
19129
19130
19131
19132
19133
19134
19135
19136
19137
19138
19139
19140
19141
19142
19143
19144
19145
19146
19147
19148
19149
19150
19151
19152
19153
// 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)
msgHdr = msgbase.get_msg_header(pByIdx, pMsgIdxOrNum, pExpandFields);
if (pMsgbase == null)
msgbase.close();
}
return msgHdr;
}
19154
19155
19156
19157
19158
19159
19160
19161
19162
19163
19164
19165
19166
19167
19168
19169
19170
19171
19172
19173
19174
19175
19176
19177
19178
19179
19180
19181
19182
19183
19184
19185
19186
19187
19188
19189
19190
19191
19192
19193
19194
19195
19196
19197
19198
19199
19200
19201
19202
19203
19204
19205
19206
19207
19208
19209
19210
19211
19212
19213
19214
19215
19216
19217
19218
19219
19220
19221
19222
19223
19224
19225
19226
19227
19228
19229
19230
19231
19232
19233
19234
19235
19236
19237
19238
// 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)
{
19276
19277
19278
19279
19280
19281
19282
19283
19284
19285
19286
19287
19288
19289
19290
19291
19292
19293
19294
19295
19296
19297
19298
19299
19300
19301
19302
19303
19304
19305
19306
19307
19308
19309
19310
19311
19312
19313
19314
19315
19316
19317
// 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;
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
if (gIsSysop)
{
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;
}
19323
19324
19325
19326
19327
19328
19329
19330
19331
19332
19333
19334
19335
19336
19337
19338
19339
19340
19341
19342
19343
19344
19345
19346
19347
19348
19349
19350
19351
19352
19353
19354
19355
19356
19357
19358
19359
19360
19361
19362
19363
19364
19365
19366
19367
19368
19369
19370
19371
19372
19373
19374
19375
19376
19377
19378
19379
19380
19381
19382
19383
19384
19385
19386
19387
19388
19389
19390
19391
19392
19393
19394
19395
19396
19397
19398
19399
19400
19401
19402
19403
19404
19405
19406
19407
19408
19409
19410
19411
19412
19413
19414
19415
19416
19417
19418
19419
19420
19421
// 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;
}
19422
19423
19424
19425
19426
19427
19428
19429
19430
19431
19432
19433
19434
19435
19436
19437
19438
19439
19440
19441
19442
19443
19444
19445
19446
19447
19448
19449
19450
19451
19452
19453
19454
19455
19456
19457
19458
19459
19460
19461
19462
19463
19464
19465
19466
19467
19468
19469
19470
19471
19472
19473
19474
19475
19476
19477
19478
19479
19480
19481
19482
19483
19484
19485
19486
19487
19488
19489
19490
19491
19492
19493
19494
19495
19496
19497
19498
19499
19500
19501
19502
19503
19504
19505
19506
19507
// 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;
}
19508
19509
19510
19511
19512
19513
19514
19515
19516
19517
19518
19519
19520
19521
19522
19523
19524
19525
19526
19527
19528
19529
19530
19531
19532
19533
19534
19535
19536
19537
19538
// 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
function getMsgUpDownvotesAndScore(pMsgHdr)
{
var retObj = {
foundVoteInfo: false,
upvotes: 0,
downvotes: 0,
voteScore: 0
};
if (pMsgHdr.hasOwnProperty("total_votes") && pMsgHdr.hasOwnProperty("upvotes"))
{
retObj.foundVoteInfo = true;
retObj.upvotes = pMsgHdr.upvotes;
retObj.downvotes = pMsgHdr.total_votes - pMsgHdr.upvotes;
retObj.voteScore = pMsgHdr.upvotes - retObj.downvotes;
}
return retObj;
}
// Writes some text on the screen at a given location with a given pause.
//
// Parameters:
// pX: The column number on the screen at which to write the message
// pY: The row number on the screen at which to write the message
// pText: The text to write
// pPauseMS: The pause time, in milliseconds
// pClearLineAttrib: Optional - The color/attribute to clear the line with.
// If not specified or null is specified, defaults to normal attribute.
// pClearLineAfter: Whether or not to clear the line again after the message is dispayed and
// the pause occurred. This is optional.
function writeWithPause(pX, pY, pText, pPauseMS, pClearLineAttrib, pClearLineAfter)
{
var clearLineAttrib = "\1n";
if ((pClearLineAttrib != null) && (typeof(pClearLineAttrib) == "string"))
clearLineAttrib = pClearLineAttrib;
console.gotoxy(pX, pY);
console.cleartoeol(clearLineAttrib);
console.print(pText);
if (pPauseMS > 0)
mswait(pPauseMS);
if (pClearLineAfter)
{
console.gotoxy(pX, pY);
console.cleartoeol(clearLineAttrib);
}
}