Merge branch 'master' into dependabot/npm_and_yarn/http-cache-semantics-4.1.1

This commit is contained in:
Bryan Ashby 2023-08-23 21:49:10 -06:00 committed by GitHub
commit 993bdbe484
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 722 additions and 488 deletions

View File

@ -8,6 +8,7 @@ This document attempts to track **major** changes and additions in ENiGMA½. For
* Routes for the file base now default to `/_f/` prefixed instead of just `/f/`. If `/f/` is in your `config.hjson` you are encouraged to update it!
* Finally, the system will search for `index.html` and `index.htm` in that order, if another suitable route cannot be established.
* CombatNet has shut down, so the module (`combatnet.js`) has been removed.
* The Menu Flag `popParent` has been removed and `noHistory` has been updated to work as expected. In general things should "Just Work", but check your `menu.hjson` entries if you see menu stack issues.
## 0.0.13-beta
* **Note for contributors**: ENiGMA has switched to [Prettier](https://prettier.io) for formatting/style. Please see [CONTRIBUTING](CONTRIBUTING.md) and the Prettier website for more information.

View File

@ -595,7 +595,7 @@
}
}
messageBaseSearchMessageList: {
messageBaseSearchResultsMessageList: {
config: {
allViewsInfoFormat10: "|00|15{msgNumSelected:>4.4} |08/ |15{msgNumTotal:<4.4}"
// Fri Sep 25th
@ -1364,4 +1364,4 @@
}
}
}
}
}

View File

@ -2,10 +2,8 @@
'use strict';
// ENiGMA½
const MenuModule = require('./menu_module.js').MenuModule;
const ViewController = require('./view_controller.js').ViewController;
const { MenuModule, MenuFlags } = require('./menu_module.js');
const ansi = require('./ansi_term.js');
const theme = require('./theme.js');
const FileEntry = require('./file_entry.js');
const stringFormat = require('./string_format.js');
const FileArea = require('./file_base_area.js');
@ -77,6 +75,8 @@ exports.getModule = class FileAreaList extends MenuModule {
this.fileList = _.get(options, 'extraArgs.fileList');
this.lastFileNextExit = _.get(options, 'extraArgs.lastFileNextExit', true);
this.setMergedFlag(MenuFlags.NoHistory);
if (this.fileList) {
// we'll need to adjust position as well!
this.fileListPosition = 0;

View File

@ -2,7 +2,7 @@
'use strict';
// enigma-bbs
const MenuModule = require('./menu_module.js').MenuModule;
const { MenuModule, MenuFlags } = require('./menu_module.js');
const { getSortedAvailableFileAreas } = require('./file_base_area.js');
const StatLog = require('./stat_log.js');
const SysProps = require('./system_property.js');
@ -24,6 +24,8 @@ exports.getModule = class FileAreaSelectModule extends MenuModule {
constructor(options) {
super(options);
this.setMergedFlag(MenuFlags.NoHistory);
this.menuMethods = {
selectArea: (formData, extraArgs, cb) => {
const filterCriteria = {
@ -34,7 +36,7 @@ exports.getModule = class FileAreaSelectModule extends MenuModule {
extraArgs: {
filterCriteria: filterCriteria,
},
menuFlags: ['popParent', 'mergeFlags'],
menuFlags: [ MenuFlags.NoHistory ],
};
return this.gotoMenu(

View File

@ -2,10 +2,8 @@
'use strict';
// ENiGMA½
const MenuModule = require('./menu_module.js').MenuModule;
const ViewController = require('./view_controller.js').ViewController;
const { MenuModule, MenuFlags } = require('./menu_module.js');
const DownloadQueue = require('./download_queue.js');
const theme = require('./theme.js');
const ansi = require('./ansi_term.js');
const Errors = require('./enig_error.js').Errors;
const FileAreaWeb = require('./file_area_web.js');
@ -38,6 +36,8 @@ exports.getModule = class FileBaseDownloadQueueManager extends MenuModule {
constructor(options) {
super(options);
this.setMergedFlag(MenuFlags.NoHistory);
this.dlQueue = new DownloadQueue(this.client);
if (_.has(options, 'lastMenuResult.sentFileIds')) {

View File

@ -121,7 +121,6 @@ exports.getModule = class FileBaseSearch extends MenuModule {
extraArgs: {
filterCriteria: filterCriteria,
},
menuFlags: ['popParent'],
};
return this.gotoMenu(

View File

@ -2,7 +2,7 @@
'use strict';
// ENiGMA½
const { MenuModule } = require('./menu_module.js');
const { MenuModule, MenuFlags } = require('./menu_module.js');
const FileEntry = require('./file_entry.js');
const FileArea = require('./file_base_area.js');
const { renderSubstr } = require('./string_util.js');
@ -65,6 +65,9 @@ const MciViewIds = {
exports.getModule = class FileBaseListExport extends MenuModule {
constructor(options) {
super(options);
this.setMergedFlag(MenuFlags.NoHistory);
this.config = Object.assign(
{},
_.get(options, 'menuConfig.config'),

View File

@ -2,10 +2,8 @@
'use strict';
// ENiGMA½
const MenuModule = require('./menu_module.js').MenuModule;
const ViewController = require('./view_controller.js').ViewController;
const { MenuModule, MenuFlags } = require('./menu_module.js');
const DownloadQueue = require('./download_queue.js');
const theme = require('./theme.js');
const ansi = require('./ansi_term.js');
const Errors = require('./enig_error.js').Errors;
const FileAreaWeb = require('./file_area_web.js');
@ -40,6 +38,8 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
constructor(options) {
super(options);
this.setMergedFlag(MenuFlags.NoHistory);
this.dlQueue = new DownloadQueue(this.client);
this.menuMethods = {

View File

@ -20,6 +20,23 @@ const assert = require('assert');
const _ = require('lodash');
const iconvDecode = require('iconv-lite').decode;
const MenuFlags = {
// When leaving this menu to load/chain to another, remove this
// menu from history. In other words, the fallback from
// the next menu would *not* be this one, but the previous.
NoHistory: 'noHistory',
// Generally used in code only: Request that any flags from menu.hjson
// are merged in to the total set of flags vs overriding the default.
MergeFlags: 'mergeFlags',
// Forward this menu's 'extraArgs' to the next.
ForwardArgs: 'forwardArgs',
};
exports.MenuFlags = MenuFlags;
exports.MenuModule = class MenuModule extends PluginModule {
constructor(options) {
super(options);
@ -48,6 +65,11 @@ exports.MenuModule = class MenuModule extends PluginModule {
});
}
setMergedFlag(flag) {
this.menuConfig.config.menuFlags.push(flag);
this.menuConfig.config.menuFlags = [...new Set([...this.menuConfig.config.menuFlags, MenuFlags.MergeFlags])];
}
static get InterruptTypes() {
return {
Never: 'never',

View File

@ -5,12 +5,12 @@
const loadMenu = require('./menu_util.js').loadMenu;
const { Errors, ErrorReasons } = require('./enig_error.js');
const { getResolvedSpec } = require('./menu_util.js');
const { MenuFlags } = require('./menu_module.js');
// deps
const _ = require('lodash');
const assert = require('assert');
// :TODO: Stack is backwards.... top should be most recent! :)
const bunyan = require('bunyan');
module.exports = class MenuStack {
constructor(client) {
@ -27,19 +27,11 @@ module.exports = class MenuStack {
}
peekPrev() {
if (this.stackSize > 1) {
return this.stack[this.stack.length - 2];
}
return this.stack[this.stack.length - 2];
}
top() {
if (this.stackSize > 0) {
return this.stack[this.stack.length - 1];
}
}
get stackSize() {
return this.stack.length;
return this.stack[this.stack.length - 1];
}
get currentModule() {
@ -56,13 +48,13 @@ module.exports = class MenuStack {
return cb(
Array.isArray(menuConfig.next)
? Errors.MenuStack(
'No matching condition for "next"',
ErrorReasons.NoConditionMatch
)
'No matching condition for "next"',
ErrorReasons.NoConditionMatch
)
: Errors.MenuStack(
'Invalid or missing "next" member in menu config',
ErrorReasons.InvalidNextMenu
)
'Invalid or missing "next" member in menu config',
ErrorReasons.InvalidNextMenu
)
);
}
@ -81,7 +73,6 @@ module.exports = class MenuStack {
prev(cb) {
const menuResult = this.top().instance.getMenuResult();
// :TODO: leave() should really take a cb...
this.pop().instance.leave(); // leave & remove current
const previousModuleInfo = this.pop(); // get previous
@ -129,7 +120,7 @@ module.exports = class MenuStack {
client: self.client,
};
if (currentModuleInfo && currentModuleInfo.menuFlags.includes('forwardArgs')) {
if (currentModuleInfo && currentModuleInfo.menuFlags.includes(MenuFlags.ForwardArgs)) {
loadOpts.extraArgs = currentModuleInfo.extraArgs;
} else {
loadOpts.extraArgs = options.extraArgs || _.get(options, 'formData.value');
@ -138,7 +129,6 @@ module.exports = class MenuStack {
loadMenu(loadOpts, (err, modInst) => {
if (err) {
// :TODO: probably should just require a cb...
const errCb = cb || self.client.defaultHandlerMissingMod();
errCb(err);
} else {
@ -151,22 +141,6 @@ module.exports = class MenuStack {
return;
}
//
// Handle deprecated 'options' block by merging to config and warning user.
// :TODO: Remove in 0.0.10+
//
if (modInst.menuConfig.options) {
self.client.log.warn(
{ options: modInst.menuConfig.options },
'Use of "options" is deprecated. Move relevant members to "config" block! Support will be fully removed in future versions'
);
Object.assign(
modInst.menuConfig.config || {},
modInst.menuConfig.options
);
delete modInst.menuConfig.options;
}
//
// If menuFlags were supplied in menu.hjson, they should win over
// anything supplied in code.
@ -180,9 +154,9 @@ module.exports = class MenuStack {
// in code we can ask to merge in
if (
Array.isArray(options.menuFlags) &&
options.menuFlags.includes('mergeFlags')
options.menuFlags.includes(MenuFlags.MergeFlags)
) {
menuFlags = _.uniq(menuFlags.concat(options.menuFlags));
menuFlags = [...new Set(options.menuFlags)]; // make unique
}
}
@ -193,12 +167,8 @@ module.exports = class MenuStack {
currentModuleInfo.instance.leave();
if (currentModuleInfo.menuFlags.includes('noHistory')) {
this.pop();
}
if (menuFlags.includes('popParent')) {
this.pop().instance.leave(); // leave & remove current
if (currentModuleInfo.menuFlags.includes(MenuFlags.NoHistory)) {
this.pop().instance.leave(); // leave & remove current from stack
}
}
@ -214,17 +184,19 @@ module.exports = class MenuStack {
modInst.restoreSavedState(options.savedState);
}
const stackEntries = self.stack.map(stackEntry => {
let name = stackEntry.name;
if (stackEntry.instance.menuConfig.config.menuFlags.length > 0) {
name += ` (${stackEntry.instance.menuConfig.config.menuFlags.join(
', '
)})`;
}
return name;
});
if (self.client.log.level() <= bunyan.TRACE) {
const stackEntries = self.stack.map(stackEntry => {
let name = stackEntry.name;
if (stackEntry.instance.menuConfig.config.menuFlags.length > 0) {
name += ` (${stackEntry.instance.menuConfig.config.menuFlags.join(
', '
)})`;
}
return name;
});
self.client.log.trace({ stack: stackEntries }, 'Updated menu stack');
self.client.log.trace({ stack: stackEntries }, 'Updated menu stack');
}
modInst.enter();

View File

@ -113,7 +113,6 @@ exports.getModule = class MessageBaseSearch extends MenuModule {
const returnNoResults = () => {
return this.gotoMenu(
this.menuConfig.config.noResultsMenu || 'messageSearchNoResults',
{ menuFlags: ['popParent'] },
cb
);
};
@ -160,7 +159,6 @@ exports.getModule = class MessageBaseSearch extends MenuModule {
messageList,
noUpdateLastReadId: true,
},
menuFlags: ['popParent'],
};
return this.gotoMenu(

View File

@ -55,6 +55,8 @@ const helpText = `
|03/|11topic |03<message> |08- |07Set the room topic
|03/|11bbses |08& |03/|11info <id> |08- |07Info about BBS's connected
|03/|11meetups |08- |07Info about MRC MeetUps
|03/|11quote |08- |07Send raw command to server
|03/|11help |08- |07Server-side commands help
---
|03/|11l33t |03<your message> |08- |07l337 5p34k
|03/|11kewl |03<your message> |08- |07BBS KeWL SPeaK
@ -375,6 +377,18 @@ exports.getModule = class mrcModule extends MenuModule {
'|08' + currentTime + '|00 ' + message.body + '|00'
);
}
// Deliver PrivMsg
else if (
message.to_user.toLowerCase() == this.state.alias.toLowerCase()
) {
const currentTime = moment().format(
this.client.currentTheme.helpers.getTimeFormat()
);
this.addMessageToChatLog(
'|08' + currentTime + '|00 ' + message.body + '|00'
);
}
}
this.viewControllers.mrcChat.switchFocus(MciViewIds.mrcChat.inputArea);
@ -540,6 +554,46 @@ exports.getModule = class mrcModule extends MenuModule {
this.sendServerMessage('LIST');
break;
// Allow support for new server commands without change to client
case 'quote':
this.sendServerMessage(`${message.substr(7)}`);
break;
/**
* Process known additional server commands directly
*/
case 'afk':
this.sendServerMessage(`AFK ${message.substr(5)}`);
break;
case 'roomconfig':
this.sendServerMessage(`ROOMCONFIG ${message.substr(12)}`);
break;
case 'roompass':
this.sendServerMessage(`ROOMPASS ${message.substr(12)}`);
break;
case 'status':
this.sendServerMessage(`STATUS ${message.substr(8)}`);
break;
case 'lastseen':
this.sendServerMessage(`LASTSEEN ${message.substr(10)}`);
break;
case 'help':
this.sendServerMessage(`HELP ${message.substr(6)}`);
break;
case 'statistics':
case 'changelog':
case 'listbans':
case 'listmutes':
case 'routing':
this.sendServerMessage(cmd[0].toUpperCase());
break;
case 'quit':
return this.prevMenu();

View File

@ -2,7 +2,7 @@
'use strict';
// ENiGMA½
const { MenuModule } = require('./menu_module.js');
const { MenuModule, MenuFlags } = require('./menu_module.js');
const messageArea = require('./message_area.js');
const { Errors } = require('./enig_error.js');
const UserProps = require('./user_property.js');
@ -29,6 +29,9 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
constructor(options) {
super(options);
// always include noHistory flag
this.setMergedFlag(MenuFlags.NoHistory);
this.initList();
this.menuMethods = {
@ -49,7 +52,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
extraArgs: {
areaTag: area.areaTag,
},
menuFlags: ['popParent', 'noHistory'],
menuFlags: [ MenuFlags.NoHistory ],
};
return this.gotoMenu(

View File

@ -2,7 +2,7 @@
'use strict';
// ENiGMA½
const { MenuModule } = require('./menu_module.js');
const { MenuModule, MenuFlags } = require('./menu_module.js');
const messageArea = require('./message_area.js');
const { Errors } = require('./enig_error.js');
@ -26,6 +26,9 @@ exports.getModule = class MessageConfListModule extends MenuModule {
constructor(options) {
super(options);
// always include noHistory flag
this.setMergedFlag(MenuFlags.NoHistory);
this.initList();
this.menuMethods = {
@ -49,7 +52,7 @@ exports.getModule = class MessageConfListModule extends MenuModule {
extraArgs: {
confTag: conf.confTag,
},
menuFlags: ['popParent', 'noHistory'],
menuFlags: [ MenuFlags.NoHistory ],
};
return this.gotoMenu(

View File

@ -2,7 +2,7 @@
'use strict';
// ENiGMA½
const MenuModule = require('./menu_module.js').MenuModule;
const { MenuModule, MenuFlags } = require('./menu_module');
const Message = require('./message.js');
const UserProps = require('./user_property.js');
const { filterMessageListByReadACS } = require('./message_area.js');
@ -16,6 +16,7 @@ exports.moduleInfo = {
exports.getModule = class MyMessagesModule extends MenuModule {
constructor(options) {
super(options);
this.setMergedFlag(MenuFlags.NoHistory);
}
initSequence() {
@ -49,7 +50,6 @@ exports.getModule = class MyMessagesModule extends MenuModule {
if (!this.messageList || 0 === this.messageList.length) {
return this.gotoMenu(
this.menuConfig.config.noResultsMenu || 'messageSearchNoResults',
{ menuFlags: ['popParent'] }
);
}
@ -58,7 +58,6 @@ exports.getModule = class MyMessagesModule extends MenuModule {
messageList: this.messageList,
noUpdateLastReadId: true,
},
menuFlags: ['popParent'],
};
return this.gotoMenu(

View File

@ -182,6 +182,14 @@ General Information:
MessageBase: `usage: oputil.js mb <action> [<arguments>]
Actions:
list-confs List conferences and areas
post PATH Posts a message file specified in PATH.
PATH must point to a UTF-8 encoded JSON file
containing 'to', 'from', 'subject', 'areaTag', and
'body'. If 'timestamp' is present, the system will
attempt to use it.
areafix CMD1 CMD2 ... ADDR Sends an AreaFix NetMail
NetMail is sent to supplied address with the supplied command(s). Multi-part commands
@ -194,6 +202,9 @@ Actions:
packet in the directory specified by PATH. The QWK
BBS ID will be obtained by the final component of PATH.
list-confs arguments:
--areas Include areas within each message conference.
import-areas arguments:
--conf CONF_TAG Conference tag in which to import areas
--network NETWORK Network name/key to associate FTN areas

View File

@ -692,6 +692,162 @@ function exportQWKPacket() {
);
}
const listConferences = () => {
initConfigAndDatabases(err => {
if (err) {
return console.error(err.reason ? err.reason : err.message);
}
const { getSortedAvailMessageConferences } = require('../../core/message_area');
const conferences = getSortedAvailMessageConferences(null, { noClient: true });
for (let conf of conferences) {
console.info(`${conf.confTag} - ${conf.conf.name}`);
if (!argv.areas) {
continue;
}
for (let areaTag of Object.keys(conf.conf.areas)) {
console.info(` ${areaTag} - ${conf.conf.areas[areaTag].name}`);
}
}
});
};
const postMessage = () => {
const inputFile = argv._[argv._.length - 1];
if (argv._.length < 3 || !inputFile || 0 === inputFile.length) {
return printUsageAndSetExitCode(getHelpFor('MessageBase'), ExitCodes.ERROR);
}
async.waterfall(
[
callback => {
return initConfigAndDatabases(callback);
},
callback => {
fs.readFile(inputFile, { encoding: 'utf-8' }, (err, jsonData) => {
if (err) {
return callback(err);
}
let messageJson;
try {
messageJson = JSON.parse(jsonData);
} catch (e) {
return callback(e);
}
for (let f of ['to', 'from', 'subject', 'body', 'areaTag']) {
if (!_.isString(messageJson[f])) {
return callback(
Errors.MissingConfig(
`Missing "${f}" field in message JSON`
)
);
}
messageJson[f] = messageJson[f].trim();
if (messageJson[f].length === 0 && f !== 'subject') {
return callback(
Errors.Invalid(
`"${messageJson[f]}" is not a valid value for the "${f}" field`
)
);
}
}
const { getMessageAreaByTag } = require('../../core/message_area');
const area = getMessageAreaByTag(messageJson.areaTag);
if (!area) {
return callback(
Errors.DoesNotExist(
`Area "${messageJson.areaTag}" does not exist`
)
);
}
const { getAddressedToInfo } = require('../../core/mail_util');
const Message = require('../../core/message');
const toInfo = getAddressedToInfo(messageJson.to);
const fromInfo = getAddressedToInfo(messageJson.from);
if (fromInfo.flavor !== Message.AddressFlavor.Local) {
return callback(
Errors.Invalid(
'Only local "from" users are currently supported'
)
);
}
let modTimestamp;
if (_.isString(messageJson.timestamp)) {
modTimestamp = moment(messageJson.timestamp);
}
if (!modTimestamp || !modTimestamp.isValid()) {
modTimestamp = moment();
}
const message = new Message({
toUserName: messageJson.to,
fromUserName: messageJson.from,
subject: messageJson.subject,
message: messageJson.body,
areaTag: messageJson.areaTag,
modTimestamp,
});
if (toInfo.flavor !== Message.AddressFlavor.Local) {
message.setExternalFlavor(toInfo.flavor);
message.setRemoteToUser(toInfo.remote);
return callback(null, area, message);
}
const User = require('../../core/user');
User.getUserIdAndNameByLookup(
message.toUserName,
(err, toUserId, toUserName) => {
if (err) {
return callback(
Errors.DoesNotExist(
`User "${message.toUserName}" does not exist.`
)
);
}
message.to = toUserName; // adjust case/etc.
message.setLocalToUserId(toUserId);
return callback(null, area, message);
}
);
});
},
(area, message, callback) => {
message.persist(err => {
if (!err) {
console.info(
`Message from ${message.fromUserName} to ${message.toUserName}: "${message.subject}" in ${area.name}`
);
}
return callback(err);
});
},
],
err => {
if (err) {
return console.error(err.reason ? err.reason : err.message);
}
}
);
};
function handleMessageBaseCommand() {
function errUsage() {
return printUsageAndSetExitCode(getHelpFor('MessageBase'), ExitCodes.ERROR);
@ -709,6 +865,8 @@ function handleMessageBaseCommand() {
'import-areas': importAreas,
'qwk-dump': dumpQWKPacket,
'qwk-export': exportQWKPacket,
'list-confs': listConferences,
post: postMessage,
}[action] || errUsage
)();
}

View File

@ -172,7 +172,7 @@ exports.getModule = class RumorzModule extends MenuModule {
StatLog.getSystemLogEntries(
SystemLogKeys.UserAddedRumorz,
StatLog.Order.Timestamp,
StatLog.Order.TimestampDesc,
(err, entries) => {
return callback(err, entriesView, entries);
}

View File

@ -219,7 +219,8 @@ exports.getModule = class MrcModule extends ServerModule {
connectedSockets.forEach(client => {
if (
message.to_user == '' ||
message.to_user == client.username ||
// Fix PrivMSG delivery on case mismatch
message.to_user.toUpperCase() == client.username.toUpperCase() ||
message.to_user == 'CLIENT' ||
message.from_user == client.username ||
message.to_user == 'NOTME'

View File

@ -557,17 +557,24 @@ exports.getModule = class GopherModule extends ServerModule {
this.makeItem(ItemTypes.InfoMessage, `Messages in ${area.name}`),
this.makeItem(ItemTypes.InfoMessage, '(newest first)'),
this.makeItem(ItemTypes.InfoMessage, '-'.repeat(70)),
...msgList.map(msg =>
this.makeItem(
...msgList.map(msg => {
let m;
try {
m = moment(msg.modTimestamp);
} catch (e) {
this.log.warn(
`Error parsing "${msg.modTimestamp}"; expected timestamp: ${e.message}`
);
m = moment();
}
return this.makeItem(
ItemTypes.TextFile,
`${moment(msg.modTimestamp).format(
'YYYY-MM-DD hh:mma'
)}: ${this.shortenSubject(msg.subject)} (${
msg.fromUserName
} to ${msg.toUserName})`,
`${m.format('YYYY-MM-DD hh:mma')}: ${this.shortenSubject(
msg.subject
)} (${msg.fromUserName} to ${msg.toUserName})`,
`/msgarea/${confTag}/${areaTag}/${msg.messageUuid}`
)
),
);
}),
].join('');
this.log.debug({ confTag, areaTag }, 'Gopher serving message list');

View File

@ -4,7 +4,6 @@
// ENiGMA½
const MenuModule = require('./menu_module.js').MenuModule;
const Errors = require('../core/enig_error.js').Errors;
const ANSI = require('./ansi_term.js');
const Config = require('./config.js').get;
const { getMessageAreaByTag } = require('./message_area.js');
@ -21,6 +20,7 @@ exports.moduleInfo = {
exports.getModule = class ShowArtModule extends MenuModule {
constructor(options) {
super(options);
this.config = Object.assign({}, _.get(options, 'menuConfig.config'), {
extraArgs: options.extraArgs,
});

View File

@ -2,7 +2,7 @@
'use strict';
// enigma-bbs
const MenuModule = require('./menu_module.js').MenuModule;
const { MenuModule, MenuFlags } = require('./menu_module');
const stringFormat = require('./string_format.js');
const getSortedAvailableFileAreas =
require('./file_base_area.js').getSortedAvailableFileAreas;
@ -76,6 +76,8 @@ exports.getModule = class UploadModule extends MenuModule {
constructor(options) {
super(options);
this.setMergedFlag(MenuFlags.NoHistory);
this.interrupt = MenuModule.InterruptTypes.Never;
if (_.has(options, 'lastMenuResult.recvFilePaths')) {

View File

@ -8,10 +8,10 @@ const theme = require('./theme.js');
const sysValidate = require('./system_view_validate.js');
const UserProps = require('./user_property.js');
const { getISOTimestampString } = require('./database.js');
const EnigAssert = require('./enigma_assert');
// deps
const async = require('async');
const assert = require('assert');
const _ = require('lodash');
const moment = require('moment');
@ -109,7 +109,10 @@ exports.getModule = class UserConfigModule extends MenuModule {
// Handlers
//
saveChanges: function (formData, extraArgs, cb) {
assert(formData.value.password === formData.value.passwordConfirm);
EnigAssert(formData.value.password === formData.value.passwordConfirm);
// cache a copy of |formData| as changing a theme below can invalidate it
formData = _.clone(formData);
const newProperties = {
[UserProps.RealName]: formData.value.realName,
@ -126,7 +129,7 @@ exports.getModule = class UserConfigModule extends MenuModule {
self.availThemeInfo[formData.value.theme].themeId,
};
// runtime set theme
// Runtime set theme
theme.setClientTheme(self.client, newProperties.theme_id);
// persist all changes

View File

@ -1,7 +1,7 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (7.0.4.1)
activesupport (7.0.7.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
@ -9,7 +9,7 @@ GEM
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
colorator (1.1.0)
concurrent-ruby (1.1.10)
concurrent-ruby (1.2.2)
cssminify2 (2.0.1)
em-websocket (0.5.3)
eventmachine (>= 0.12.9)
@ -24,7 +24,7 @@ GEM
nokogiri (>= 1.4)
htmlcompressor (0.4.0)
http_parser.rb (0.8.0)
i18n (1.12.0)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
jekyll (4.2.1)
addressable (~> 2.4)
@ -76,13 +76,13 @@ GEM
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.4.0)
minitest (5.17.0)
nokogiri (1.13.6-x86_64-linux)
minitest (5.19.0)
nokogiri (1.14.3-x86_64-linux)
racc (~> 1.4)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (4.0.6)
racc (1.6.0)
racc (1.6.2)
rb-fsevent (0.11.0)
rb-inotify (0.10.1)
ffi (~> 1.0)
@ -93,7 +93,7 @@ GEM
ffi (~> 1.9)
terminal-table (2.0.0)
unicode-display_width (~> 1.1, >= 1.1.1)
tzinfo (2.0.5)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)

View File

@ -323,7 +323,7 @@ qwk-export arguments:
| Action | Description | Examples |
|-----------|-------------------|---------------------------------------|
| `import-areas` | Imports areas using a FidoNet style *.NA or AREAS.BBS formatted file. Optionally maps areas to FTN networks. | `./oputil.js config import-areas /some/path/l33tnet.na` |
| `import-areas` | Imports areas using a FidoNet style *.NA or AREAS.BBS formatted file. Optionally maps areas to FTN networks. | `./oputil.js mb import-areas /some/path/l33tnet.na` |
| `areafix` | Utility for sending AreaFix mails without logging into the system | |
| `qwk-dump` | Dump a QWK packet to stdout | `./oputil.js mb qwk-dump /path/to/XIBALBA.QWK` |
| `qwk-export` | Export messages to a QWK packet | `./oputil.js mb qwk-export /path/to/XIBALBA.QWK` |

View File

@ -59,13 +59,15 @@ The `config` block for a menu entry can contain common members as well as a per-
| `menuFlags` | An array of menu flag(s) controlling menu behavior. See **Menu Flags** below.
#### Menu Flags
The `menuFlags` field of a `config` block can change default behavior of a particular menu.
The `menuFlags` field of a `config` block can change default behavior of a particular menu:
| Flag | Description |
|------|-------------|
| `noHistory` | Prevents the menu from remaining in the menu stack / history. When this flag is set, when the **next** menu falls back, this menu will be skipped and the previous menu again displayed instead. Example: menuA -> menuB(noHistory) -> menuC: Exiting menuC returns the user to menuA. |
| `popParent` | When *this* menu is exited, fall back beyond the parent as well. Often used in combination with `noHistory`. |
| `forwardArgs` | If set, when the next menu is entered, forward any `extraArgs` arguments to *this* menu on to it. |
| `noHistory` | When leaving the current menu to load/chain to another, remove this menu from history. In other words, the fallback from the next menu would *not* be this one, but the previous. |
| `mergeFlags` | Generally used in code only: Request that any flags from `menu.hjson` |
| `forwardArgs` | Forward this menu's `extraArgs` to the next. |
> 💡 In JavaScript code, `MenuFlags` from `menu_module.js` contains constants for these flags.
## Forms

View File

@ -58,7 +58,6 @@ showFileBaseAreaArt: {
method: fileBaseArea
cls: true
pause: true
menuFlags: [ "popParent", "noHistory" ]
}
}
```

View File

@ -101,6 +101,6 @@ webserver, and unpack it to a temporary directory.
otherwise.
9. If you navigate to http://your-hostname.here/vtx.html, you should see a splash screen like the following:
![VTXClient](../assets/images/vtxclient.png "VTXClient")
![VTXClient](../../assets/images/vtxclient.png "VTXClient")

View File

@ -315,6 +315,8 @@
chatServers: {
// multi relay chat settings. No need to sign up, just enable it.
// More info: https://bbswiki.bottomlessabyss.net/index.php?title=MRC_Chat_platform
// Make sure to adjust 'prettyBoardName' to your liking in your config before enabling
mrc: {
enabled : false
serverHostname : 'mrc.bottomlessabyss.net'

View File

@ -388,7 +388,7 @@
art: FEMPTYQ
config: {
pause: true
menuFlags: [ "noHistory", "popParent" ]
menuFlags: [ "noHistory" ]
}
}
@ -779,7 +779,7 @@
art: FBNORES
config: {
pause: true
menuFlags: [ "noHistory", "popParent" ]
menuFlags: [ "noHistory" ]
}
}
@ -807,7 +807,7 @@
art: FBNORES
config: {
pause: true
menuFlags: [ "noHistory", "popParent" ]
menuFlags: [ "noHistory" ]
}
}
@ -852,7 +852,7 @@
art: ULNOAREA
config: {
pause: true
menuFlags: [ "noHistory", "popParent" ]
menuFlags: [ "noHistory" ]
}
}

View File

@ -776,7 +776,7 @@
key: confTag
pause: true
cls: true
menuFlags: [ "popParent", "noHistory" ]
menuFlags: [ "noHistory" ]
}
}
@ -794,7 +794,7 @@
key: areaTag
pause: true
cls: true
menuFlags: [ "popParent", "noHistory" ]
menuFlags: [ "noHistory" ]
}
}
}

View File

@ -57,7 +57,7 @@
"rlogin": "^1.0.0",
"sane": "5.0.1",
"sanitize-filename": "^1.6.3",
"sqlite3": "5.0.11",
"sqlite3": "5.1.6",
"sqlite3-trans": "1.3.0",
"ssh2": "1.11.0",
"systeminformation": "5.12.3",

737
yarn.lock

File diff suppressed because it is too large Load Diff