Newer
Older

nightfox
committed
break;
}
// If no messages were found, then output a message to say so with a momentary pause.
if (newMsgOffset == -1)
{
if (pPositionCursorForStatus)
{
console.gotoxy(1, console.screen_rows);
console.cleartoeol();
console.gotoxy(this.msgAreaLeft, console.screen_rows);
}
else
console.crlf();
console.print("\1n\1h\1yNo messages found.\1n");
mswait(ERROR_PAUSE_WAIT_MS);
}
return newMsgOffset;
}
// For the DigDistMsgReader class: Calculates the top message index for a page,
// for the traditional-style message list.
//
// Parameters:
// pPageNum: A page number (1-based)
function DigDistMsgReader_CalcTraditionalMsgListTopIdx(pPageNum)
{
if (this.reverseListOrder)
this.tradListTopMsgIdx = this.NumMessages() - (this.tradMsgListNumLines * (pPageNum-1)) - 1;
else
this.tradListTopMsgIdx = (this.tradMsgListNumLines * (pPageNum-1));
}
// For the DigDistMsgReader class: Calculates the top message index for a page,
// for the lightbar message list.
//
// Parameters:
// pPageNum: A page number (1-based)
function DigDistMsgReader_CalcLightbarMsgListTopIdx(pPageNum)
{
if (this.reverseListOrder)
this.lightbarListTopMsgIdx = this.NumMessages() - (this.lightbarMsgListNumLines * (pPageNum-1)) - 1;
else
{
//this.lightbarListTopMsgIdx = (this.lightbarMsgListNumLines * (pPageNum-1));
var pageIdx = pPageNum - 1;
if (pageIdx < 0)
pageIdx = 0;
this.lightbarListTopMsgIdx = this.lightbarMsgListNumLines * pageIdx;
}
}
// For the DigDistMsgReader class: Given a message number (1-based), this calculates
// the screen index veriables (stored in the object) for the message list. This is
// used for the enhanced reader mode when we want the message list to be in the
// correct place for the message being read.
//
// Parameters:
// pMsgNum: The message number (1-based)
function DigDistMsgReader_CalcMsgListScreenIdxVarsFromMsgNum(pMsgNum)
{
// Calculate the message list variables
var numItemsPerPage = this.tradMsgListNumLines;
if (this.msgListUseLightbarListInterface && canDoHighASCIIAndANSI())
numItemsPerPage = this.lightbarMsgListNumLines;
var newPageNum = findPageNumOfItemNum(pMsgNum, numItemsPerPage, this.NumMessages(), this.reverseListOrder);
this.CalcTraditionalMsgListTopIdx(newPageNum);
this.CalcLightbarMsgListTopIdx(newPageNum);
this.lightbarListSelectedMsgIdx = pMsgNum - 1;
if (this.lightbarListCurPos == null)
this.lightbarListCurPos = {};
this.lightbarListCurPos.x = 1;
13074
13075
13076
13077
13078
13079
13080
13081
13082
13083
13084
13085
13086
13087
13088
13089
13090
13091
13092
13093
13094
13095
13096
this.lightbarListCurPos.y = this.lightbarMsgListStartScreenRow + ((pMsgNum-1) - this.lightbarListTopMsgIdx);
}
// For the DigDistMsgReader class: Validates a user's choice in message area.
// Returns a status/error message for the caller to display if there's an
// error. This function outputs intermediate status messages (i.e.,
// "Searching..").
//
// Parameters:
// pGrpIdx: The message group index (i.e., bbs.curgrp)
// pSubIdx: The message sub-board index (i.e., bbs.cursub)
// pCurPos: Optional - An object containing x and y properties representing
// the cursor position. Used for outputting intermediate status
// messages, but not for outputting the error message.
//
// Return value: An object containing the following properties:
// msgAreaGood: A boolean to indicate whether the message area
// can be selected
// errorMsg: If the message area can't be selected, this string
// will contain an eror message. Otherwise, this will
// be an empty string.
function DigDistMsgReader_ValidateMsgAreaChoice(pGrpIdx, pSubIdx, pCurPos)
{
var retObj = {
msgAreaGood: true,
errorMsg: ""
};
13101
13102
13103
13104
13105
13106
13107
13108
13109
13110
13111
13112
13113
13114
13115
13116
13117
13118
13119
13120
13121
13122
13123
13124
13125
13126
13127
13128
13129
13130
13131
13132
13133
13134
13135
// Get the internal code of the sub-board from the given group & sub-board
// indexes
var subCode = msg_area.grp_list[pGrpIdx].sub_list[pSubIdx].code;
// If a search is specified that would populate the search results, then do
// a search in the given sub-board.
if (this.SearchTypePopulatesSearchResults())
{
// See if we can use pCurPos to move the cursor before displaying messages
var useCurPos = (console.term_supports(USER_ANSI) && (typeof(pCurPos) == "object") &&
(typeof(pCurPos.x) == "number") && (typeof(pCurPos.y) == "number"));
// TODO: In case new messages were posted in this sub-board, it might help
// to check the current number of messages vs. the previous number of messages
// and search the new messages if there are more.
// Determine whether or not to search - If there are no search results for
// the given sub-board already, then do a search in the sub-board.
var doSearch = true;
if (this.msgSearchHdrs.hasOwnProperty(subCode) &&
(typeof(this.msgSearchHdrs[subCode]) == "object") &&
(typeof(this.msgSearchHdrs[subCode].indexed) != "undefined"))
{
doSearch = (this.msgSearchHdrs[subCode].indexed.length == 0);
}
if (doSearch)
{
if (useCurPos)
{
console.gotoxy(pCurPos);
console.cleartoeol("\1n");
console.gotoxy(pCurPos);
}
console.print("\1n\1h\1wSearching\1i...\1n");
this.msgSearchHdrs[subCode] = searchMsgbase(subCode, this.searchType, this.searchString, this.readingPersonalEmailFromUser);
// If there are no messages, then set the return object variables to indicate so.
if (this.msgSearchHdrs[subCode].indexed.length == 0)
{
retObj.msgAreaGood = false;
retObj.errorMsg = "No search results found";
13142
13143
13144
13145
13146
13147
13148
13149
13150
13151
13152
13153
13154
13155
13156
13157
13158
13159
13160
13161
13162
13163
}
}
}
else
{
// No search is specified. Just check to see if there are any messages
// to read in the given sub-board.
var msgBase = new MsgBase(subCode);
if (msgBase.open())
{
if (msgBase.total_msgs == 0)
{
retObj.msgAreaGood = false;
retObj.errorMsg = "No messages in that message area";
}
msgBase.close();
}
}
return retObj;
}
// For the DigDistMsgReader class: Validates a message if the sub-board
// requires message validation.
//
// Parameters:
// pSubBoardCode: The internal code of the sub-board
// pMsgNum: The message number
//
// Return value: Boolean - Whether or not validating the message was successful
function DigDistMsgReader_ValidateMsg(pSubBoardCode, pMsgNum)
{
if (!msg_area.sub[pSubBoardCode].is_moderated)
return true;
var validationSuccessful = false;
var msgbase = new MsgBase(this.subBoardCode);
if (msgbase.open())
{
var msgHdr = msgbase.get_msg_header(false, pMsgNum, false);
if (msgHdr != null)
{
if ((msgHdr.attr & MSG_VALIDATED) == 0)
{
msgHdr.attr |= MSG_VALIDATED;
validationSuccessful = msgbase.put_msg_header(false, msgHdr.number, msgHdr);
}
else
validationSuccessful = true;
}
msgbase.close();
}
return validationSuccessful;
}
13198
13199
13200
13201
13202
13203
13204
13205
13206
13207
13208
13209
13210
13211
13212
13213
13214
13215
13216
13217
13218
// For the DigDistMsgReader class: Gets the current sub-board's group name and description.
//
// Return value: An object with the following properties:
// grpName: The group name
// grpDesc: The group description
function DigDistMsgReader_GetGroupNameAndDesc()
{
var retObj = {
grpName: "",
grpDesc: ""
}
var msgbase = new MsgBase(this.subBoardCode);
if (msgbase.open())
{
retObj.grpName = msgbase.cfg.grp_name;
retObj.grpDesc = msgbase.cfg.description;
msgbase.close();
}
return retObj;
}
13219
13220
13221
13222
13223
13224
13225
13226
13227
13228
13229
13230
13231
13232
13233
13234
13235
13236
13237
13238
13239
13240
13241
13242
13243
13244
13245
13246
13247
13248
13249
13250
13251
13252
13253
13254
13255
13256
13257
13258
13259
13260
13261
// For the DigDistMsgReader class: Writes message lines to a file on the BBS
// machine.
//
// Parameters:
// pMsgHdr: The header object for the message
// pFilename: The name of the file to write the message to
// pStripCtrl: Boolean - Whether or not to remove Synchronet control
// codes from the message lines
// pMsgLines: An array containing the message lines
// pAttachments: An array containing attachment information (as returned by determineMsgAttachments())
//
// Return value: An object containing the following properties:
// succeeded: Boolean - Whether or not the file was successfully written
// errorMsg: String - On failure, will contain the reason it failed
function DigDistMsgReader_SaveMsgToFile(pMsgHdr, pFilename, pStripCtrl, pMsgLines, pAttachments)
{
// Sanity checking
if (typeof(pFilename) != "string")
return({ succeeded: false, errorMsg: "Filename parameter not a string"});
if (pFilename.length == 0)
return({ succeeded: false, errorMsg: "Empty filename given"});
// If no message lines are passed in, then get the message lines now.
var msgLines = pMsgLines;
var attachments = pAttachments;
if ((pMsgLines == null) || (typeof(pMsgLines) != "object"))
{
if (typeof(pMsgHdr) == "object")
{
// Get the message text, interpret any @-codes in it, replace tabs with spaces
// to prevent weirdness when displaying the message lines, and word-wrap the
// text so that it looks good on the screen,
//GetMsgInfoForEnhancedReader(pMsgHdr, pWordWrap, pDetermineAttachments, pGetB64Data)
//var msgInfo = this.GetMsgInfoForEnhancedReader(pMsgHdr, false, false, false);
var msgInfo = this.GetMsgInfoForEnhancedReader(pMsgHdr, true, true, true);
msgLines = msgInfo.messageLines;
if (msgInfo.hasOwnProperty("attachments"))
attachments = msgInfo.attachments;
}
else
return({ succeeded: false, errorMsg: "No message lines and null header object"});
}
var retObj = {
succeeded: true,
errorMsg: ""
};
13266
13267
13268
13269
13270
13271
13272
13273
13274
13275
13276
13277
13278
13279
13280
13281
13282
13283
13284
13285
13286
13287
13288
13289
13290
13291
13292
13293
13294
13295
13296
13297
13298
13299
13300
13301
13302
13303
13304
13305
13306
13307
13308
13309
13310
13311
13312
13313
13314
13315
13316
13317
13318
13319
13320
13321
13322
13323
13324
13325
13326
13327
13328
13329
13330
13331
13332
13333
13334
13335
13336
13337
13338
13339
13340
13341
13342
13343
13344
13345
13346
13347
13348
13349
13350
13351
13352
13353
13354
13355
13356
13357
13358
13359
13360
13361
13362
13363
13364
13365
13366
13367
13368
13369
13370
13371
13372
13373
13374
// If there are message attachments, then treat pFilename as a directory and
// create the directory for saving both the message text & attachments.
// Then, save the attachments to that directory.
var msgTextFilename = pFilename;
if ((attachments != null) && (attachments.length > 0))
{
if (file_isdir(pFilename))
{
if (file_exists(pFilename))
return({ succeeded: false, errorMsg: "Can't make directory: File with that name exists"});
}
else
{
if (!mkdir(pFilename))
return({ succeeded: false, errorMsg: "Failed to create directory"});
}
// The name of the file to save the message text will be called "messageText.txt"
// in the save directory.
var savePathWithTrailingSlash = backslash(pFilename);
msgTextFilename = savePathWithTrailingSlash + "messageText.txt";
// Save the attachments to the directory
var saveFileError = "";
for (var attachIdx = 0; (attachIdx < attachments.length) && (saveFileError.length == 0); ++attachIdx)
{
var destFilename = savePathWithTrailingSlash + attachments[attachIdx].filename;
// If the file info has base64 data, then decode & save it to the directory.
// Otherwise, the file was probably uploaded to the user's mailbox in Synchronet,
// so copy the file to the save directory.
if (attachments[attachIdx].hasOwnProperty("B64Data"))
{
var attachedFile = new File(destFilename);
if (attachedFile.open("wb"))
{
attachedFile.base64 = true;
if (!attachedFile.write(attachments[attachIdx].B64Data))
saveFileError = "\1n\1cFailed to save " + attachments[attachIdx].filename;
attachedFile.close();
}
}
else
{
// There is no base64 data for the file, so it's probably in the
// user's mailbox in Synchronet, so copy it to the save directory.
if (file_exists(attachments[attachIdx].fullyPathedFilename))
{
if (!file_copy(attachments[attachIdx].fullyPathedFilename, destFilename))
saveFileError = "Failed to copy " + attachments[attachIdx].filename;
}
else
saveFileError = "File " + attachments[attachIdx].fullyPathedAttachmentFilename + " doesn't exist";
}
}
if (saveFileError.length > 0)
return({ succeeded: false, errorMsg: saveFileError });
}
var messageSaveFile = new File(msgTextFilename);
if (messageSaveFile.open("w"))
{
// Write some header information to the file
if (typeof(pMsgHdr) == "object")
{
if (pMsgHdr.hasOwnProperty("from"))
messageSaveFile.writeln("From: " + pMsgHdr.from);
if (pMsgHdr.hasOwnProperty("to"))
messageSaveFile.writeln(" To: " + pMsgHdr.to);
if (pMsgHdr.hasOwnProperty("subject"))
messageSaveFile.writeln("Subj: " + pMsgHdr.subject);
/*
if (pMsgHdr.hasOwnProperty("when_written_time"))
messageSaveFile.writeln(strftime("Date: %Y-%m-%d %H:%M:%S", msgHeader.when_written_time));
*/
if (pMsgHdr.hasOwnProperty("date"))
messageSaveFile.writeln("Date: " + pMsgHdr.date);
if (pMsgHdr.hasOwnProperty("from_net_addr"))
messageSaveFile.writeln("From net address: " + pMsgHdr.from_net_addr);
if (pMsgHdr.hasOwnProperty("to_net_addr"))
messageSaveFile.writeln("To net address: " + pMsgHdr.to_net_addr);
if (pMsgHdr.hasOwnProperty("id"))
messageSaveFile.writeln("ID: " + pMsgHdr.id);
if (pMsgHdr.hasOwnProperty("reply_id"))
messageSaveFile.writeln("Reply ID: " + pMsgHdr.reply_id);
messageSaveFile.writeln("===============================");
}
// Write the message body to the file
if (pStripCtrl)
{
for (var msgLineIdx = 0; msgLineIdx < msgLines.length; ++msgLineIdx)
messageSaveFile.writeln(strip_ctrl(msgLines[msgLineIdx]));
}
else
{
for (var msgLineIdx = 0; msgLineIdx < msgLines.length; ++msgLineIdx)
messageSaveFile.writeln(msgLines[msgLineIdx]);
}
messageSaveFile.close();
}
else
{
retObj.succeeded = false;
retObj.errorMsg = "Unable to open the message file for writing";
}
return retObj;
}
13375
13376
13377
13378
13379
13380
13381
13382
13383
13384
13385
13386
13387
13388
13389
13390
13391
13392
13393
// For the DigDistMsgReader class: Toggles whether a message has been 'selected'
// (i.e., for things like batch delete, etc.)
//
// Parameters:
// pSubCode: The internal sub-board code of the message sub-board where the
// message resides
// pMsgIdx: The index of the message to toggle
// pSelected: Optional boolean to explictly specify whether the message should
// be selected. If this is not provided (or is null), then this
// message will simply toggle the selection state of the message.
function DigDistMsgReader_ToggleSelectedMessage(pSubCode, pMsgIdx, pSelected)
{
// Sanity checking
if (typeof(pSubCode) != "string") return;
if (typeof(pMsgIdx) != "number") return;
// If the 'selected message' object doesn't have the sub code index,
// then add it.
if (!this.selectedMessages.hasOwnProperty(pSubCode))
this.selectedMessages[pSubCode] = {};
13395
13396
13397
13398
13399
13400
13401
13402
13403
13404
13405
13406
13407
13408
13409
13410
13411
13412
13413
13414
13415
13416
13417
13418
13419
13420
13421
13422
13423
13424
13425
13426
13427
13428
13429
13430
13431
13432
13433
13434
13435
13436
13437
13438
13439
13440
13441
13442
// If pSelected is a boolean, then it specifies the specific selection
// state of the message (true = selected, false = not selected).
if (typeof(pSelected) == "boolean")
{
if (pSelected)
{
if (!this.selectedMessages[pSubCode].hasOwnProperty(pMsgIdx))
this.selectedMessages[pSubCode][pMsgIdx] = true;
}
else
{
if (this.selectedMessages[pSubCode].hasOwnProperty(pMsgIdx))
delete this.selectedMessages[pSubCode][pMsgIdx];
}
}
else
{
// pSelected is not a boolean, so simply toggle the selection state of
// the message.
// If the object for the given sub-board code contains the message
// index, then remove it. Otherwise, add it.
if (this.selectedMessages[pSubCode].hasOwnProperty(pMsgIdx))
delete this.selectedMessages[pSubCode][pMsgIdx];
else
this.selectedMessages[pSubCode][pMsgIdx] = true;
}
}
// For the DigDistMsgReader class: Returns whether a message (by sub-board code & index)
// is selected (i.e., for batch delete, etc.).
//
// Parameters:
// pSubCode: The internal sub-board code of the message sub-board where the
// message resides
// pMsgIdx: The index of the message to toggle
//
// Return value: Boolean - Whether or not the given message has been selected
function DigDistMsgReader_MessageIsSelected(pSubCode, pMsgIdx)
{
return (this.selectedMessages.hasOwnProperty(pSubCode) && this.selectedMessages[pSubCode].hasOwnProperty(pMsgIdx));
}
// For the DigDistMsgReader class: Checks to see if all selected messages can
// be deleted (i.e., whether the user has permission to delete all of them).
function DigDistMsgReader_AllSelectedMessagesCanBeDeleted()
{
// If the user has sysop access, then they should be able to delete messages.
Eric Oulashin
committed
if (user.is_sysop)
13444
13445
13446
13447
13448
13449
13450
13451
13452
13453
13454
13455
13456
13457
13458
13459
13460
13461
13462
13463
13464
13465
13466
13467
13468
13469
13470
13471
13472
13473
13474
13475
13476
13477
13478
13479
13480
13481
return true;
var userCanDeleteAllSelectedMessages = true;
var msgBase = null;
for (var subBoardCode in this.selectedMessages)
{
// If the current sub-board is personal mail, then the user can delete
// those messages. Otherwise, check the sub-board configuration to see
// if the user can delete messages in the sub-board.
if (subBoardCode != "mail")
{
msgBase = new MsgBase(subBoardCode);
if (msgBase.open())
{
userCanDeleteAllSelectedMessages = userCanDeleteAllSelectedMessages && ((msgBase.cfg.settings & SUB_DEL) == SUB_DEL);
msgBase.close();
}
}
if (!userCanDeleteAllSelectedMessages)
break;
}
return userCanDeleteAllSelectedMessages;
}
// For the DigDistMsgReader class: Marks the 'selected messages' (in
// this.selecteMessages) as deleted. Returns an object with the following
// properties:
// deletedAll: Boolean - Whether or not all messages were successfully marked
// for deletion
// failureList: An object containing indexes of messages that failed to get
// marked for deletion, indexed by internal sub-board code, then
// containing messages indexes as properties. Reasons for failing
// to mark messages deleted can include the user not having permission
// to delete in a sub-board, failure to open the sub-board, etc.
function DigDistMsgReader_DeleteSelectedMessages()
{
var retObj = {
deletedAll: true,
failureList: {}
};
var msgBase = null;
var msgHdr = null;
var msgWasDeleted = false;
for (var subBoardCode in this.selectedMessages)
{
msgBase = new MsgBase(subBoardCode);
if (msgBase.open())
{
// Allow the user to delete the messages if they're the sysop, they're
// reading their personal mail, or the sub-board allows deleting messages.
Eric Oulashin
committed
if (user.is_sysop || (subBoardCode == "mail") || ((msgBase.cfg.settings & SUB_DEL) == SUB_DEL))
{
for (var msgIdx in this.selectedMessages[subBoardCode])
{
// It seems that msgIdx is a string, so make sure we have a
// numeric version.
var msgIdxNumber = +msgIdx;
// If doing a search (this.msgSearchHdrs has the sub-board code),
// then get the message header by index from there. Otherwise,
// use the message base object to get the message by index.
if (this.msgSearchHdrs.hasOwnProperty(subBoardCode) &&
(this.msgSearchHdrs[subBoardCode].indexed.length > 0))
{
if ((msgIdxNumber >= 0) && (msgIdxNumber < this.msgSearchHdrs[subBoardCode].indexed.length))
msgHdr = this.msgSearchHdrs[subBoardCode].indexed[msgIdxNumber];
}

nightfox
committed
else if (this.hdrsForCurrentSubBoard.length > 0)
{
if ((msgIdxNumber >= 0) && (msgIdxNumber < this.hdrsForCurrentSubBoard.length))
msgHdr = this.hdrsForCurrentSubBoard[msgIdxNumber];
}
else
{
if ((msgIdxNumber >= 0) && (msgIdxNumber < msgBase.total_msgs))
msgHdr = msgBase.get_msg_header(true, msgIdxNumber, false);
}
// If we got the message header, then mark it for deletion.
// If the message header wasn't marked as deleted, then add
// the message index to the return object.
if (msgHdr != null)
{
//msgWasDeleted = msgBase.remove_msg(true, msgHdr.offset);
msgWasDeleted = msgBase.remove_msg(false, msgHdr.number);
}
else
msgWasDeleted = false;
if (msgWasDeleted)
{

nightfox
committed
// Refresh the message header in the header arrays (if it
// exists there) and remove the message index from the
// selectedMessages object

nightfox
committed
this.RefreshHdrInSavedArrays(msgIdxNumber, MSG_DELETE, subBoardCode);
delete this.selectedMessages[subBoardCode][msgIdx];

nightfox
committed
// Delete any vote response messages that may exist for this message
var voteDelRetObj = deleteVoteMsgs(msgBase, msgHdr.number, msgHdr.id, (subBoardCode == "mail"));

nightfox
committed
// TODO: If the main messages was deleted, does it matter if vote response messages
// are deleted?
if (!voteDelRetObj.allVoteMsgsDeleted)
{
retObj.deletedAll = false;
if (!retObj.failureList.hasOwnProperty(subBoardCode))
retObj.failureList[subBoardCode] = [];

nightfox
committed
retObj.failureList[subBoardCode].push(msgIdxNumber);
}
}
else
{
retObj.deletedAll = false;
if (!retObj.failureList.hasOwnProperty(subBoardCode))
retObj.failureList[subBoardCode] = [];
13558
13559
13560
13561
13562
13563
13564
13565
13566
13567
13568
13569
13570
13571
13572
13573
13574
retObj.failureList[subBoardCode].push(msgIdxNumber);
}
}
// If the sub-board index array no longer has any properties (i.e.,
// all messages in the sub-board were marked as deleted), then remove
// the sub-board property from this.selectedMessages
if (Object.keys(this.selectedMessages[subBoardCode]).length == 0)
delete this.selectedMessages[subBoardCode];
}
else
{
// The user doesn't have permission to delete messages
// in this sub-board.
// Create an entry in retObj.failureList indexed by the
// sub-board code to indicate failure to delete all
// messages in the sub-board.
retObj.deletedAll = false;
retObj.failureList[subBoardCode] = [];
}
msgBase.close();
}
else
{
// Failure to open the sub-board.
// Create an entry in retObj.failureList indexed by the
// sub-board code to indicate failure to delete all messages
// in the sub-board.
retObj.deletedAll = false;
retObj.failureList[subBoardCode] = [];
13588
13589
13590
13591
13592
13593
13594
13595
13596
13597
13598
13599
13600
13601
13602
13603
13604
}
}
return retObj;
}
// For the DigDistMsgReader class: Returns the number of selected messages
function DigDistMsgReader_NumSelectedMessages()
{
var numSelectedMsgs = 0;
for (var subBoardCode in this.selectedMessages)
numSelectedMsgs += Object.keys(this.selectedMessages[subBoardCode]).length;
return numSelectedMsgs;
}

nightfox
committed
// Allows the user to forward a message to an email address or
// another user. This function is interactive with the user.
//
// Parameters:
// pMsgHeader: The header of the message being forwarded
// pMsgBody: The body text of the message
//
// Return value: A blank string on success or a string containing a
// message upon failure.
function DigDistMsgReader_ForwardMessage(pMsgHdr, pMsgBody)
{
if (typeof(pMsgHdr) != "object")
return "Invalid message header given";
var retStr = "";

Eric Oulashin
committed

nightfox
committed
console.print("\1n");
console.crlf();
console.print("\1cUser name/number/email address\1h:\1n");
console.crlf();
var msgDest = console.getstr(console.screen_columns - 1, K_LINE);
console.print("\1n");
console.crlf();
if (msgDest.length > 0)
{
var tmpMsgbase = new MsgBase("mail");
if (tmpMsgbase.open())
{
// If the given message body is not a string, then get the
// message body from the messagebase.
if (typeof(pMsgBody) != "string")
{
var msgbase = new MsgBase(this.subBoardCode);
if (msgbase.open())
{
pMsgBody = msgbase.get_msg_body(false, pMsgHdr.number, false, false, true, true);
msgbase.close();
}
else
return "Unable to open the sub-board to get the message body";
}

nightfox
committed
13647
13648
13649
13650
13651
13652
13653
13654
13655
13656
13657
13658
13659
13660
13661
13662
13663
13664
13665
13666
13667
// Prepend some lines to the message body to describe where
// the message came from originally.
var newMsgBody = "This is a forwarded message from " + system.name + "\n";
newMsgBody += "Forwarded by: " + user.alias;
if (user.alias != user.name)
newMsgBody += " (" + user.name + ")";
newMsgBody += "\n";
if (this.subBoardCode == "mail")
newMsgBody += "From " + user.name + "'s personal email\n";
else
{
newMsgBody += "From sub-board: "
+ msg_area.grp_list[msg_area.sub[this.subBoardCode].grp_index].description
+ ", " + msg_area.sub[this.subBoardCode].description + "\n";
}
newMsgBody += "From: " + pMsgHdr.from + "\n";
newMsgBody += "To: " + pMsgHdr.to + "\n";
newMsgBody += "Subject: " + pMsgHdr.subject + "\n";
newMsgBody += "==================================\n\n";
newMsgBody += pMsgBody;
// Ask whether to edit the message before forwarding it,
13669
13670
13671
13672
13673
13674
13675
13676
13677
13678
13679
13680
13681
13682
13683
13684
13685
13686
13687
13688
13689
13690
13691
13692
13693
13694
13695
13696
13697
13698
13699
13700
13701
13702
13703
13704
13705
13706
13707
13708
13709
13710
13711
13712
13713
13714
13715
13716
// and use console.editfile(filename) to edit it.
if (!console.noyes("Edit the message before sending"))
{
var baseWorkDir = system.node_dir + "DDMsgReader_Temp";
deltree(baseWorkDir + "/");
if (mkdir(baseWorkDir))
{
// TODO: Let the user edit the message, then read it
// and set newMsgBody to it
var tmpMsgFilename = baseWorkDir + "/message.txt";
// Write the current message to the file
var wroteMsgToTmpFile = false;
var outFile = new File(tmpMsgFilename);
if (outFile.open("w"))
{
wroteMsgToTmpFile = outFile.write(newMsgBody, newMsgBody.length);
outFile.close();
}
if (wroteMsgToTmpFile)
{
// Let the user edit the file, and if successful,
// read it in to newMsgBody
if (console.editfile(tmpMsgFilename))
{
var inFile = new File(tmpMsgFilename);
if (inFile.open("r"))
{
newMsgBody = inFile.read(inFile.length);
inFile.close();
}
}
}
else
{
console.print("\1n\1cFailed to write message to a file for editing\1n");
console.crlf();
console.pause();
}
}
else
{
console.print("\1n\1cCouldn't create temporary directory\1n");
console.crlf();
console.pause();
}
}
// End New (editing message)

nightfox
committed
// Create part of a header object which will be used when saving/sending
// the message. The destination ("to" informatoin) will be filled in
// according to the destination type.
var destMsgHdr = { to_net_type: NET_NONE, from: user.name,
replyto: user.name, subject: "Fwd: " + pMsgHdr.subject };
if (user.netmail.length > 0)

Eric Oulashin
committed
{

nightfox
committed
destMsgHdr.replyto_net_addr = user.netmail;

Eric Oulashin
committed
}

nightfox
committed
else

Eric Oulashin
committed
{

nightfox
committed
destMsgHdr.replyto_net_addr = user.email;

Eric Oulashin
committed
}

nightfox
committed
//destMsgHdr.when_written_time =
//destMsgHdr.when_written_zone = system.timezone;
//destMsgHdr.when_written_zone_offset =
var confirmedForwardMsg = true;
// If the destination is in the format anything@anything, then
// accept it as the message destination. It could be an Internet
// address (someone@somewhere.com), FidoNet address (sysop@1:327/4),
// or a QWK address (someone@HOST).
// We could specifically use gEmailRegex and gFTNEmailregex to test
// msgDest, but just using those would be too restrictive.
if (/^.*@.*$/.test(msgDest))

nightfox
committed
{
confirmedForwardMsg = console.yesno("Forward via email to " + msgDest);
if (confirmedForwardMsg)
{
console.print("\1n\1cForwarding via email to " + msgDest + "\1n");
console.crlf();
destMsgHdr.to = msgDest;
destMsgHdr.to_net_addr = msgDest;

Eric Oulashin
committed
destMsgHdr.to_net_type = netaddr_type(msgDest);

nightfox
committed
13752
13753
13754
13755
13756
13757
13758
13759
13760
13761
13762
13763
13764
13765
13766
13767
13768
13769
13770
13771
13772
13773
13774
13775
13776
13777
13778
13779
13780
13781
13782
13783
13784
13785
13786
13787
13788
13789
13790
13791
13792
13793
13794
13795
13796
13797
13798
13799
13800
}
}
else
{
// See if what the user entered is a user number/name/alias
var userNum = 0;
if (/^[0-9]+$/.test(msgDest))
{
userNum = +msgDest;
// Determine if the user entered a valid user number
var lastUserNum = (system.lastuser == undefined ? system.stats.total_users : system.lastuser + 1);
if ((userNum < 1) || (userNum >= lastUserNum))
{
userNum = 0;
console.print("\1h\1y* Invalid user number (" + msgDest + ")\1n");
console.crlf();
}
}
else // Try to get a user number assuming msgDest is a username/alias
userNum = system.matchuser(msgDest, true);
// If we have a valid user number, then we can forward the message.
if (userNum > 0)
{
var destUser = new User(userNum);
confirmedForwardMsg = console.yesno("Forward to " + destUser.alias + " (user " + destUser.number + ")");
if (confirmedForwardMsg)
{
destMsgHdr.to = destUser.alias;
// If the destination user has an Internet email address,
// ask the user if they want to send to the destination
// user's Internet email address
var sendToNetEmail = false;
if (destUser.netmail.length > 0)
{
sendToNetEmail = !console.noyes("Send to the user's Internet email (" + destUser.netmail + ")");
if (sendToNetEmail)
{
console.print("\1n\1cForwarding to " + destUser.netmail + "\1n");
console.crlf();
destMsgHdr.to = destUser.name;
destMsgHdr.to_net_addr = destUser.netmail;
destMsgHdr.to_net_type = NET_INTERNET;
}
}
if (!sendToNetEmail)
{
console.print("\1n\1cForwarding to " + destUser.alias + "\1n");
console.crlf();
destMsgHdr.to_ext = destUser.number;

Eric Oulashin
committed
destMsgHdr.to_net_type = NET_NONE;

nightfox
committed
13802
13803
13804
13805
13806
13807
13808
13809
13810
13811
13812
13813
13814
13815
13816
13817
13818
13819
13820
13821
13822
13823
13824
13825
13826
13827
13828
13829
13830
13831
13832
13833
13834
13835
13836
13837
13838
13839
13840
13841
13842
13843
}
}
}
else
{
confirmedForwardMsg = false;
console.print("\1h\1y* Unknown destination\1n");
console.crlf();
}
}
var savedMsg = true;
if (confirmedForwardMsg)
savedMsg = tmpMsgbase.save_msg(destMsgHdr, newMsgBody);
else
{
console.print("\1n\1cCanceled\1n");
console.crlf();
}
tmpMsgbase.close();
if (!savedMsg)
{
console.print("\1h\1y* Failed to send the message!\1n");
console.crlf();
}
// Pause for user input so the user can see the messages written
console.pause();
}
else
retStr = "Failed to open email messagebase";
}
else
{
console.print("\1n\1cCanceled\1n");
console.crlf();
console.pause();
}
return retStr;
}

Eric Oulashin
committed
13844
13845
13846
13847
13848
13849
13850
13851
13852
13853
13854
13855
13856
13857
13858
13859
13860
13861
13862
13863
13864
13865
13866
13867
13868
13869
13870
13871
13872
13873
13874
13875
13876
13877
13878
13879
13880
13881
13882
13883
13884
13885
13886
13887
13888
13889
13890
13891
function printMsgHdrInfo(pMsgHdr)
{
if (typeof(pMsgHdr) != "object")
return;
for (var prop in pMsgHdr)
{
if (prop == "to_net_type")
print(prop + ": " + toNetTypeToStr(pMsgHdr[prop]));
else
console.print(prop + ": " + pMsgHdr[prop]);
console.crlf();
}
}
function toNetTypeToStr(toNetType)
{
var toNetTypeStr = "Unknown";
if (typeof(toNetType) == "number")
{
switch (toNetType)
{
case NET_NONE:
toNetTypeStr = "Local";
break;
case NET_UNKNOWN:
toNetTypeStr = "Unknown networked";
break;
case NET_FIDO:
toNetTypeStr = "FidoNet";
break;
case NET_POSTLINK:
toNetTypeStr = "PostLink";
break;
case NET_QWK:
toNetTypeStr = "QWK";
break;
case NET_INTERNET:
toNetTypeStr = "Internet";
break;
default:
toNetTypeStr = "Unknown";
break;
}
}
return toNetTypeStr;
}
// For the DigDistMsgReader class: Lets the user vote on a message
//
// Parameters:
// pMsgHdr: The header of the mesasge being voted on
// pRemoveNLsFromVoteText: Optional boolean - Whether or not to remove newlines
// (and carriage returns) from the voting text from
// text.dat. Defaults to false.
//
// Return value: An object with the following properties:
// BBSHasVoteFunction: Boolean - Whether or not the system has
// the vote_msg function
// savedVote: Boolean - Whether or not the vote was saved
// userQuit: Boolean - Whether or not the user quit and didn't vote
// errorMsg: String - An error message, if something went wrong
// mnemonicsRequiredForErrorMsg: Boolean - Whether or not mnemonics is required to print the error message
// updatedHdr: The updated message header containing vote information.
// If something went wrong, this will be null.
function DigDistMsgReader_VoteOnMessage(pMsgHdr, pRemoveNLsFromVoteText)
var retObj = {
BBSHasVoteFunction: false,
savedVote: false,
userQuit: false,
errorMsg: "",
mnemonicsRequiredForErrorMsg: false,
updatedHdr: null
};

nightfox
committed
// Don't allow voting for personal email
if (this.subBoardCode == "mail")
{
retObj.errorMsg = "Can not vote on personal email";
return retObj;
}
// Check whether the user has the voting restiction
if ((user.security.restrictions & UFLAG_V) == UFLAG_V)
{
// Use the line from text.dat that says the user is not allowed to vote,
// and remove newlines from it.
retObj.errorMsg = "\1n" + bbs.text(typeof(R_Voting) != "undefined" ? R_Voting : 781).replace("\r\n", "").replace("\n", "").replace("\N", "").replace("\r", "").replace("\R", "").replace("\R\n", "").replace("\r\N", "").replace("\R\N", "");
return retObj;
}

nightfox
committed
var msgbase = new MsgBase(this.subBoardCode);
if (!msgbase.open())
{
return retObj;
}
// If the message vote function is not defined in the running verison of Synchronet,
// then just return.
retObj.BBSHasVoteFunction = (typeof(msgbase.vote_msg) == "function");
if (!retObj.BBSHasVoteFunction)
{
msgbase.close();
return retObj;
var removeNLsFromVoteText = (typeof(pRemoveNLsFromVoteText) === "boolean" ? pRemoveNLsFromVoteText : false)
// See if voting is allowed in the current sub-board
if ((msg_area.sub[this.subBoardCode].settings & SUB_NOVOTING) == SUB_NOVOTING)
{
retObj.errorMsg = bbs.text(typeof(VotingNotAllowed) != "undefined" ? VotingNotAllowed : 779);
if (removeNLsFromVoteText)
retObj.errorMsg = retObj.errorMsg.replace("\r\n", "").replace("\n", "").replace("\N", "").replace("\r", "").replace("\R", "").replace("\R\n", "").replace("\r\N", "").replace("\R\N", "");
retObj.mnemonicsRequiredForErrorMsg = true;
msgbase.close();
return retObj;
}
// If the message is a poll question and has the maximum number of votes
// already or is closed for voting, then don't let the user vote on it.
if ((pMsgHdr.attr & MSG_POLL) == MSG_POLL)
{
var userVotedMaxVotes = false;
var numVotes = (pMsgHdr.hasOwnProperty("votes") ? pMsgHdr.votes : 0);
if (typeof(msgbase.how_user_voted) === "function")
{
var votes = msgbase.how_user_voted(pMsgHdr.number, (msgbase.cfg.settings & SUB_NAME) == SUB_NAME ? user.name : user.alias);
// TODO: I'm not sure if this 'if' section is correct anymore for
// the latest 3.17 build of Synchronet (August 14, 2017)
// Digital Man said:
// In a poll message, the "votes" property specifies the maximum number of
// answers/votes per ballot (0 is the equivalent of 1).
// Max votes testing? :
// userVotedMaxVotes = (votes == pMsgHdr.votes);
13980
13981
13982
13983
13984
13985
13986
13987
13988
13989
13990
13991
13992
13993
13994
13995
13996
13997
13998
13999
14000
if (votes >= 0)
{
if ((votes == 0) || (votes == 1))
userVotedMaxVotes = (votes == 3); // (1 << 0) | (1 << 1);
else
{
userVotedMaxVotes = true;
for (var voteIdx = 0; voteIdx <= numVotes; ++voteIdx)
{
if (votes && (1 << voteIdx) == 0)
{
userVotedMaxVotes = false;
break;
}
}
}
}
}
var pollIsClosed = ((pMsgHdr.auxattr & POLL_CLOSED) == POLL_CLOSED);
if (pollIsClosed)
{