diff --git a/core/ansi_term.js b/core/ansi_term.js index 06bf864f..c9902c7d 100644 --- a/core/ansi_term.js +++ b/core/ansi_term.js @@ -2,15 +2,27 @@ 'use strict'; // -// ANSI Terminal Support +// ANSI Terminal Support Resources // -// Resources: -// * http://ansi-bbs.org/ -// * http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/ansisys.txt -// * http://en.wikipedia.org/wiki/ANSI_escape_code -// * https://github.com/chjj/term.js/blob/master/src/term.js -// * http://www.inwap.com/pdp10/ansicode.txt +// ANSI-BBS +// * http://ansi-bbs.org/ // +// CTerm / SyncTERM +// * https://github.com/protomouse/synchronet/blob/master/src/conio/cterm.txt +// +// BananaCom +// * http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/bansi.txt +// +// ANSI.SYS +// * http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/ansisys.txt +// * http://academic.evergreen.edu/projects/biophysics/technotes/program/ansi_esc.htm +// +// General +// * http://en.wikipedia.org/wiki/ANSI_escape_code +// * http://www.inwap.com/pdp10/ansicode.txt +// +// Other Implementations +// * https://github.com/chjj/term.js/blob/master/src/term.js // ENiGMA½ const miscUtil = require('./misc_util.js'); diff --git a/core/archive_util.js b/core/archive_util.js index 094f7d1a..1c543a12 100644 --- a/core/archive_util.js +++ b/core/archive_util.js @@ -2,7 +2,8 @@ 'use strict'; // ENiGMA½ -const Config = require('./config.js').config; +const Config = require('./config.js').config; +const stringFormat = require('./string_format.js'); // base/modules const fs = require('fs'); @@ -124,7 +125,7 @@ module.exports = class ArchiveUtil { let args = _.clone(archiver.compressArgs); // don't muck with orig for(let i = 0; i < args.length; ++i) { - args[i] = args[i].format({ + args[i] = stringFormat(args[i], { archivePath : archivePath, fileList : files.join(' '), }); @@ -144,7 +145,7 @@ module.exports = class ArchiveUtil { let args = _.clone(archiver.decompressArgs); // don't muck with orig for(let i = 0; i < args.length; ++i) { - args[i] = args[i].format({ + args[i] = stringFormat(args[i], { archivePath : archivePath, extractPath : extractPath, }); diff --git a/core/bbs.js b/core/bbs.js index ff5e996f..a0bf2ac5 100644 --- a/core/bbs.js +++ b/core/bbs.js @@ -128,10 +128,10 @@ function initialize(cb) { if(err) { console.error('Could not create path: ' + conf.config.paths[pathKey] + ': ' + err.toString()); } - next(err); + return next(err); }); }, function dirCreationComplete(err) { - callback(err); + return callback(err); }); }, function basicInit(callback) { @@ -142,22 +142,19 @@ function initialize(cb) { process.on('SIGINT', shutdownSystem); - // Init some extensions - require('string-format').extend(String.prototype, require('./string_util.js').stringFormatExtensions); - - callback(null); + return callback(null); }, function initDatabases(callback) { - database.initializeDatabases(callback); + return database.initializeDatabases(callback); }, function initStatLog(callback) { - require('./stat_log.js').init(callback); + return require('./stat_log.js').init(callback); }, function initThemes(callback) { // Have to pull in here so it's after Config init require('./theme.js').initAvailableThemes(function onThemesInit(err, themeCount) { logger.log.info({ themeCount : themeCount }, 'Themes initialized'); - callback(err); + return callback(err); }); }, function loadSysOpInformation(callback) { @@ -204,10 +201,10 @@ function initialize(cb) { ); }, function initMCI(callback) { - require('./predefined_mci.js').init(callback); + return require('./predefined_mci.js').init(callback); }, function readyMessageNetworkSupport(callback) { - require('./msg_network.js').startup(callback); + return require('./msg_network.js').startup(callback); }, function readyEventScheduler(callback) { const EventSchedulerModule = require('./event_scheduler.js').EventSchedulerModule; @@ -218,7 +215,7 @@ function initialize(cb) { } ], function onComplete(err) { - cb(err); + return cb(err); } ); } diff --git a/core/config.js b/core/config.js index a6bbe25a..b6f92ded 100644 --- a/core/config.js +++ b/core/config.js @@ -292,7 +292,17 @@ function getDefaultConfig() { }, logging : { - level : 'debug' + level : 'debug', + + rotatingFile : { // set to 'disabled' or false to disable + type : 'rotating-file', + fileName : 'enigma-bbs.log', + period : '1d', + count : 3, + level : 'debug', + } + + // :TODO: syslog - https://github.com/mcavage/node-bunyan-syslog }, debug : { diff --git a/core/door.js b/core/door.js index 457c5b3b..302de522 100644 --- a/core/door.js +++ b/core/door.js @@ -1,6 +1,9 @@ /* jslint node: true */ 'use strict'; + +const stringFormat = require('./string_format.js'); + const events = require('events'); const _ = require('lodash'); const pty = require('ptyw.js'); @@ -100,7 +103,7 @@ Door.prototype.run = function() { let args = _.clone(self.exeInfo.args); // we need a copy so the original is not modified for(let i = 0; i < args.length; ++i) { - args[i] = self.exeInfo.args[i].format({ + args[i] = stringFormat(self.exeInfo.args[i], { dropFile : self.exeInfo.dropFile, node : self.exeInfo.node.toString(), srvPort : sockServer ? sockServer.address().port.toString() : '-1', diff --git a/core/fse.js b/core/fse.js index ccff0275..414c10ef 100644 --- a/core/fse.js +++ b/core/fse.js @@ -2,17 +2,16 @@ 'use strict'; // ENiGMA½ -const MenuModule = require('../core/menu_module.js').MenuModule; -const ViewController = require('../core/view_controller.js').ViewController; -const ansi = require('../core/ansi_term.js'); -const theme = require('../core/theme.js'); -const Message = require('../core/message.js'); -const getMessageAreaByTag = require('../core/message_area.js').getMessageAreaByTag; -const updateMessageAreaLastReadId = require('../core/message_area.js').updateMessageAreaLastReadId; -const getUserIdAndName = require('../core/user.js').getUserIdAndName; -const cleanControlCodes = require('../core/string_util.js').cleanControlCodes; +const MenuModule = require('./menu_module.js').MenuModule; +const ViewController = require('./view_controller.js').ViewController; +const ansi = require('./ansi_term.js'); +const theme = require('./theme.js'); +const Message = require('./message.js'); +const updateMessageAreaLastReadId = require('./message_area.js').updateMessageAreaLastReadId; +const getUserIdAndName = require('./user.js').getUserIdAndName; +const cleanControlCodes = require('./string_util.js').cleanControlCodes; const StatLog = require('./stat_log.js'); - +const stringFormat = require('./string_format.js'); // deps const async = require('async'); @@ -851,6 +850,21 @@ function FullScreenEditorModule(options) { }); }; + this.getQuoteByHeader = function() { + let quoteFormat = this.menuConfig.config.quoteFormats; + if(Array.isArray(quoteFormat)) { + quoteFormat = quoteFormat[ Math.floor(Math.random() * quoteFormat.length) ]; + } else if(!_.isString(quoteFormat)) { + quoteFormat = 'On {dateTime} {userName} said...'; + } + + const dtFormat = this.menuConfig.config.quoteDateTimeFormat || self.client.currentTheme.helpers.getDateTimeFormat(); + return stringFormat(quoteFormat, { + dateTime : moment(self.replyToMessage.modTimestamp).format(dtFormat), + userName : self.replyToMessage.fromUserName, + }); + }; + this.menuMethods = { // // Validation stuff @@ -917,14 +931,7 @@ function FullScreenEditorModule(options) { if(self.newQuoteBlock) { self.newQuoteBlock = false; - - // :TODO: Make date/time format avail as FSE config -- also the line itself! - var dtFormat = self.client.currentTheme.helpers.getDateTimeFormat(); - quoteMsgView.addText( - 'On {0} {1} said...'.format( - moment(self.replyToMessage.modTimestamp).format(dtFormat), - self.replyToMessage.fromUserName) - ); + quoteMsgView.addText(self.getQuoteByHeader()); } var quoteText = self.viewControllers.quoteBuilder.getView(3).getItem(formData.value.quote); diff --git a/core/logger.js b/core/logger.js index 47f465f7..0d71a2fe 100644 --- a/core/logger.js +++ b/core/logger.js @@ -1,63 +1,74 @@ /* jslint node: true */ 'use strict'; -var bunyan = require('bunyan'); -var paths = require('path'); -var fs = require('fs'); +// deps +const bunyan = require('bunyan'); +const paths = require('path'); +const fs = require('fs'); +const _ = require('lodash'); -module.exports = { - init : function() { - var Config = require('./config.js').config; - //var ringBufferLimit = miscUtil.valueWithDefault(config.logRingBufferLimit, 100); - var logPath = Config.paths.logs; +module.exports = class Log { - // - // Create something a bit more friendly if the log directory cannot be used - // - // :TODO: this seems cheesy... - var logPathError; - try { - var pathStat = fs.statSync(logPath); - if(!pathStat.isDirectory()) { - logPathError = logPath + ' is not a directory!'; - } - } catch(e) { - if('ENOENT' === e.code) { - logPathError = 'No such file or directory: ' + logPath; - } else { - logPathError = e.message; - } + static init() { + const Config = require('./config.js').config; + const logPath = Config.paths.logs; + + const err = this.checkLogPath(logPath); + if(err) { + console.error(err.message); // eslint-disable-line no-console + return process.exit(); } - if(logPathError) { - console.error(logPathError); - process.exit(); + const logStreams = []; + if(_.isObject(Config.logging.rotatingFile)) { + Config.logging.rotatingFile.path = paths.join(logPath, Config.logging.rotatingFile.fileName); + logStreams.push(Config.logging.rotatingFile); } - var logFile = paths.join(logPath, 'enigma-bbs.log'); + const serializers = { + err : bunyan.stdSerializers.err, // handle 'err' fields with stack/etc. + }; - // :TODO: make this configurable -- - // user should be able to configure rotations, levels to file vs ringBuffer, - // completely disable logging, etc. + // try to remove sensitive info by default, e.g. 'password' fields + [ 'formData', 'formValue' ].forEach(keyName => { + serializers[keyName] = (fd) => Log.hideSensitive(fd); + }); this.log = bunyan.createLogger({ - name : 'ENiGMA½ BBS', - streams : [ - { - type : 'rotating-file', - path : logFile, - period : Config.logging.period || '1d', - count : 3, - level : Config.logging.level || 'debug', - } - /*, - { - type : 'raw', - stream : ringBuffer, - level : 'trace' - }*/ - ], - serializers: { err : bunyan.stdSerializers.err } // handle 'err' fields with stack/etc. + name : 'ENiGMA½ BBS', + streams : logStreams, + serializers : serializers, }); } + + static checkLogPath(logPath) { + try { + if(!fs.statSync(logPath).isDirectory()) { + return new Error(`${logPath} is not a directory`); + } + + return null; + } catch(e) { + if('ENOENT' === e.code) { + return new Error(`${logPath} does not exist`); + } + return e; + } + } + + static hideSensitive(obj) { + try { + // + // Use a regexp -- we don't know how nested fields we want to seek and destroy may be + // + return JSON.parse( + JSON.stringify(obj).replace(/"(password)"\s?:\s?"([^"]+)"/, (match, valueName) => { + return `"${valueName}":"********"`; + }) + ); + } catch(e) { + // be safe and return empty obj! + return {}; + } + } }; diff --git a/core/multi_line_edit_text_view.js b/core/multi_line_edit_text_view.js index d731e4e0..0b05747a 100644 --- a/core/multi_line_edit_text_view.js +++ b/core/multi_line_edit_text_view.js @@ -66,7 +66,7 @@ var SPECIAL_KEY_MAP_DEFAULT = { 'line feed' : [ 'return' ], exit : [ 'esc' ], backspace : [ 'backspace' ], - 'delete' : [ 'del' ], + delete : [ 'del' ], tab : [ 'tab' ], up : [ 'up arrow' ], down : [ 'down arrow' ], @@ -802,7 +802,6 @@ function MultiLineEditTextView(options) { self.emitEditPosition(); }; - //this.keyPressClearLine = function() { this.keyPressDeleteLine = function() { if(self.textLines.length > 0) { self.removeCharactersFromText( diff --git a/core/new_scan.js b/core/new_scan.js index fe8405af..f38196e4 100644 --- a/core/new_scan.js +++ b/core/new_scan.js @@ -4,7 +4,8 @@ // ENiGMA½ const msgArea = require('./message_area.js'); const MenuModule = require('./menu_module.js').MenuModule; -const ViewController = require('../core/view_controller.js').ViewController; +const ViewController = require('./view_controller.js').ViewController; +const stringFormat = require('./string_format.js'); // deps const _ = require('lodash'); @@ -120,16 +121,7 @@ function NewScanModule(options) { // :TODO: it would be nice to cache this - must be done by conf! const sortedAreas = msgArea.getSortedAvailMessageAreasByConfTag(conf.confTag, { client : self.client } ); const currentArea = sortedAreas[self.currentScanAux.area]; - - function getFormatObj() { - return { - confName : conf.conf.name, - confDesc : conf.conf.desc, - areaName : currentArea.area.name, - areaDesc : currentArea.area.desc - }; - } - + // // Scan and update index until we find something. If results are found, // we'll goto the list module & show them. @@ -147,7 +139,12 @@ function NewScanModule(options) { } }, function updateStatusScanStarted(callback) { - self.updateScanStatus(self.scanStartFmt.format(getFormatObj())); + self.updateScanStatus(stringFormat(self.scanStartFmt, { + confName : conf.conf.name, + confDesc : conf.conf.desc, + areaName : currentArea.area.name, + areaDesc : currentArea.area.desc + })); return callback(null); }, function getNewMessagesCountInArea(callback) { diff --git a/core/servers/ssh.js b/core/servers/ssh.js index 9f47da80..c45af9b6 100644 --- a/core/servers/ssh.js +++ b/core/servers/ssh.js @@ -9,6 +9,7 @@ var ServerModule = require('../server_module.js').ServerModule; var userLogin = require('../user_login.js').userLogin; var enigVersion = require('../../package.json').version; var theme = require('../theme.js'); +const stringFormat = require('../string_format.js'); var ssh2 = require('ssh2'); var fs = require('fs'); @@ -105,12 +106,12 @@ function SSHClient(clientConn) { theme.getThemeArt(artOpts, function gotArt(err, artInfo) { if(err) { interactivePrompt.prompt = 'Access denied\n' + ctx.username + '\'s password: '; - } else { - var newUserNameList = '"' + (Config.users.newUserNames || []).join(', ') + '"'; - interactivePrompt.prompt = - 'Access denied\n' + - artInfo.data.format( { newUserNames : newUserNameList } ) + - '\n' + ctx.username + '\'s password: '; + } else { + const newUserNameList = _.has(Config, 'users.newUserNames') && Config.users.newUserNames.length > 0 ? + Config.users.newUserNames.map(newName => '"' + newName + '"').join(', ') : + '(No new user names enabled!)'; + + interactivePrompt.prompt = `Access denied\n${stringFormat(artInfo.data, { newUserNames : newUserNameList })}\n${ctx.username}'s password'`; } return ctx.prompt(interactivePrompt, retryPrompt); }); diff --git a/core/string_format.js b/core/string_format.js index 70b5b813..d6f6431a 100644 --- a/core/string_format.js +++ b/core/string_format.js @@ -1,9 +1,11 @@ /* jslint node: true */ 'use strict'; -const EnigError = require('./enig_error.js').EnigError; -const pad = require('./string_util.js').pad; -const stylizeString = require('./string_util.js').stylizeString; +const EnigError = require('./enig_error.js').EnigError; +const pad = require('./string_util.js').pad; +const stylizeString = require('./string_util.js').stylizeString; +const renderStringLength = require('./string_util.js').renderStringLength; +const renderSubstr = require('./string_util.js').renderSubstr; // deps const _ = require('lodash'); @@ -124,7 +126,7 @@ function getPadAlign(align) { function formatString(value, tokens) { const fill = tokens.fill || (tokens['0'] ? '0' : ' '); const align = tokens.align || (tokens['0'] ? '=' : '<'); - const precision = Number(tokens.precision || value.length); // :TODO: consider pipe/ANSI length + const precision = Number(tokens.precision || renderStringLength(value) + 1); if('' !== tokens.type && 's' !== tokens.type) { throw new ValueError(`Unknown format code "${tokens.type}" for String object`); @@ -146,7 +148,7 @@ function formatString(value, tokens) { throw new ValueError('"=" alignment not allowed in string format specifier'); } - return pad(value.slice(0, precision), parseInt(tokens.width), fill, getPadAlign(align)); + return pad(renderSubstr(value, 0, precision), Number(tokens.width), fill, getPadAlign(align)); } const FormatNumRegExp = { @@ -167,7 +169,10 @@ function formatNumberHelper(n, precision, type) { case 'x' : return n.toString(16); case 'e' : return n.toExponential(precision).replace(FormatNumRegExp.ExponentRep, '$&0'); case 'f' : return n.toFixed(precision); - case 'g' : return n.toPrecision(precision || 1); + case 'g' : + // we don't want useless trailing zeros. parseFloat -> back to string fixes this for us + return parseFloat(n.toPrecision(precision || 1)).toString(); + case '%' : return formatNumberHelper(n * 100, precision, 'f') + '%'; case '' : return formatNumberHelper(n, precision, 'd'); @@ -276,7 +281,7 @@ const REGEXP_BASIC_FORMAT = /{([^.!:}]+(?:\.[^.!:}]+)*)(?:\!([^:}]+))?(?:\:([^}] function getValue(obj, path) { const value = _.get(obj, path); - if(value) { + if(!_.isUndefined(value)) { return _.isFunction(value) ? value() : value; } @@ -286,9 +291,16 @@ function getValue(obj, path) { module.exports = function format(fmt, obj) { const re = REGEXP_BASIC_FORMAT; + let match; let pos; let out = ''; + let objPath ; + let transformer; + let formatSpec; + let value; + let tokens; + do { pos = re.lastIndex; match = re.exec(fmt); @@ -298,16 +310,16 @@ module.exports = function format(fmt, obj) { out += fmt.slice(pos, match.index); } - const objPath = match[1]; - const transformer = match[2]; - const formatSpec = match[3]; + objPath = match[1]; + transformer = match[2]; + formatSpec = match[3]; - let value = getValue(obj, objPath); + value = getValue(obj, objPath); if(transformer) { value = transformValue(transformer, value); } - const tokens = tokenizeFormatSpec(formatSpec || ''); + tokens = tokenizeFormatSpec(formatSpec || ''); if(!isNaN(parseInt(value))) { out += formatNumber(value, tokens); @@ -323,5 +335,5 @@ module.exports = function format(fmt, obj) { out += fmt.slice(pos); } - return out; + return out; }; diff --git a/core/string_util.js b/core/string_util.js index bf8fdf9e..407f8046 100644 --- a/core/string_util.js +++ b/core/string_util.js @@ -195,45 +195,6 @@ function stringFromNullTermBuffer(buf, encoding) { return iconv.decode(buf.slice(0, nullPos), encoding || 'utf-8'); } -// -// Extend String.format's object syntax with some modifiers -// e.g.: '{username!styleL33t}'.format( { username : 'Leet User' } ) -> "L33t U53r" -// -var stringFormatExtensions = { - styleUpper : function(s) { - return stylizeString(s, 'upper'); - }, - styleLower : function(s) { - return stylizeString(s, 'lower'); - }, - styleTitle : function(s) { - return stylizeString(s, 'title'); - }, - styleFirstLower : function(s) { - return stylizeString(s, 'first lower'); - }, - styleSmallVowels : function(s) { - return stylizeString(s, 'small vowels'); - }, - styleBigVowels : function(s) { - return stylizeString(s, 'big vowels'); - }, - styleSmallI : function(s) { - return stylizeString(s, 'small i'); - }, - styleMixed : function(s) { - return stylizeString(s, 'mixed'); - }, - styleL33t : function(s) { - return stylizeString(s, 'l33t'); - } - - // :TODO: Add padding/etc. modifiers. -}; - -exports.stringFormatExtensions = stringFormatExtensions; - - // :TODO: Add other codes from ansi_escape_parser const ANSI_REGEXP = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g; const PIPE_REGEXP = /\|[A-Z\d]{2}/g; @@ -244,7 +205,7 @@ const ANSI_OR_PIPE_REGEXP = new RegExp(ANSI_REGEXP.source + '|' + PIPE_REGEXP.so // function renderSubstr(str, start, length) { start = start || 0; - length = length || str.length - start; + length = Math.max(0, (length || str.length - start) - 1); const re = ANSI_REGEXP; let pos; diff --git a/core/text_view.js b/core/text_view.js index 50bd3f85..8d8439a0 100644 --- a/core/text_view.js +++ b/core/text_view.js @@ -240,14 +240,6 @@ TextView.prototype.setText = function(text) { }; */ -TextView.prototype.setFormatObject = function(obj) { - if(!_.isObject(obj) || !this.text) { - return; - } - - this.setText(this.text.format(obj)); -}; - TextView.prototype.clearText = function() { this.setText(''); }; diff --git a/core/user_login.js b/core/user_login.js index 038a0a4b..b122b372 100644 --- a/core/user_login.js +++ b/core/user_login.js @@ -16,7 +16,7 @@ exports.userLogin = userLogin; function userLogin(client, username, password, cb) { client.user.authenticate(username, password, function authenticated(err) { if(err) { - client.log.info( { username : username }, 'Failed login attempt: %s', err); + client.log.info( { username : username, error : err.message }, 'Failed login attempt'); // :TODO: if username exists, record failed login attempt to properties // :TODO: check Config max failed logon attempts/etc. - set err.maxAttempts = true diff --git a/core/view_controller.js b/core/view_controller.js index 2cbf40b1..dcc25d31 100644 --- a/core/view_controller.js +++ b/core/view_controller.js @@ -6,6 +6,7 @@ var MCIViewFactory = require('./mci_view_factory.js').MCIViewFactory; var menuUtil = require('./menu_util.js'); var asset = require('./asset.js'); var ansi = require('./ansi_term.js'); +const Log = require('./logger.js'); // deps var events = require('events'); @@ -328,7 +329,14 @@ function ViewController(options) { } } - self.client.log.trace( { formValue : formValue, actionValue : actionValue }, 'Action match'); + self.client.log.trace( + { + formValue : formValue, + actionValue : actionValue + }, + 'Action match' + ); + return true; }; diff --git a/mods/bbs_list.js b/mods/bbs_list.js index 13e56675..9b37b24e 100644 --- a/mods/bbs_list.js +++ b/mods/bbs_list.js @@ -8,6 +8,7 @@ const ViewController = require('../core/view_controller.js').ViewController; const ansi = require('../core/ansi_term.js'); const theme = require('../core/theme.js'); const getUserName = require('../core/user.js').getUserName; +const stringFormat = require('../core/string_format.js'); // deps const async = require('async'); @@ -99,7 +100,6 @@ function BBSListModule(options) { self.setViewText(MciViewIds.view[mciName], ''); }); } else { - // :TODO: we really need pipe code support for TextView!! const youSubmittedFormat = config.youSubmittedFormat || '{submitter} (You!)'; Object.keys(SELECTED_MCI_NAME_TO_ENTRY).forEach(mciName => { @@ -107,7 +107,7 @@ function BBSListModule(options) { if(MciViewIds.view[mciName]) { if('SelectedBBSSubmitter' == mciName && entry.submitterUserId == self.client.user.userId) { - self.setViewText(MciViewIds.view.SelectedBBSSubmitter, youSubmittedFormat.format(entry)); + self.setViewText(MciViewIds.view.SelectedBBSSubmitter, stringFormat(youSubmittedFormat, entry)); } else { self.setViewText(MciViewIds.view[mciName], t); } @@ -120,8 +120,8 @@ function BBSListModule(options) { const listFormat = config.listFormat || '{bbsName}'; const focusListFormat = config.focusListFormat || '{bbsName}'; - entriesView.setItems(self.entries.map( e => listFormat.format(e) ) ); - entriesView.setFocusItems(self.entries.map( e => focusListFormat.format(e) ) ); + entriesView.setItems(self.entries.map( e => stringFormat(listFormat, e) ) ); + entriesView.setFocusItems(self.entries.map( e => stringFormat(focusListFormat, e) ) ); }; this.displayBBSList = function(clearScreen, cb) { diff --git a/mods/erc_client.js b/mods/erc_client.js index 803d1f2c..dd0f9494 100644 --- a/mods/erc_client.js +++ b/mods/erc_client.js @@ -2,6 +2,7 @@ 'use strict'; var MenuModule = require('../core/menu_module.js').MenuModule; +const stringFormat = require('../core/string_format.js'); // deps const async = require('async'); @@ -86,10 +87,10 @@ function ErcClientModule(options) { try { if(data.userName) { // user message - text = self.chatEntryFormat.format(data); + text = stringFormat(self.chatEntryFormat, data); } else { // system message - text = self.systemEntryFormat.format(data); + text = stringFormat(self.systemEntryFormat, data); } } catch(e) { return self.client.log.warn( { error : e.message }, 'ERC: chatEntryFormat error'); diff --git a/mods/last_callers.js b/mods/last_callers.js index ccb8f804..36a682a2 100644 --- a/mods/last_callers.js +++ b/mods/last_callers.js @@ -8,6 +8,7 @@ const StatLog = require('../core/stat_log.js'); const getUserName = require('../core/user.js').getUserName; const loadProperties = require('../core/user.js').loadProperties; const isRootUserId = require('../core/user.js').isRootUserId; +const stringFormat = require('../core/string_format.js'); // deps const moment = require('moment'); @@ -123,12 +124,9 @@ LastCallersModule.prototype.mciReady = function(mciData, cb) { ); }, function populateList(callback) { - const listFormat = self.menuConfig.config.listFormat || '{userName} - {location} - {affils} - {ts}'; + const listFormat = self.menuConfig.config.listFormat || '{userName} - {location} - {affiliation} - {ts}'; - callersView.setItems(_.map(loginHistory, ce => listFormat.format(ce) ) ); - - // :TODO: This is a hack until pipe codes are better implemented - callersView.focusItems = callersView.items; + callersView.setItems(_.map(loginHistory, ce => stringFormat(listFormat, ce) ) ); callersView.redraw(); return callback(null); diff --git a/mods/msg_area_list.js b/mods/msg_area_list.js index ed2d0559..85603ef4 100644 --- a/mods/msg_area_list.js +++ b/mods/msg_area_list.js @@ -8,6 +8,7 @@ const messageArea = require('../core/message_area.js'); const displayThemeArt = require('../core/theme.js').displayThemeArt; const displayThemedPause = require('../core/theme.js').displayThemedPause; const resetScreen = require('../core/ansi_term.js').resetScreen; +const stringFormat = require('../core/string_format.js'); // deps const async = require('async'); @@ -152,7 +153,7 @@ MessageAreaListModule.prototype.mciReady = function(mciData, cb) { const areaListView = vc.getView(MCICodesIDs.AreaList); let i = 1; areaListView.setItems(_.map(self.messageAreas, v => { - return listFormat.format({ + return stringFormat(listFormat, { index : i++, areaTag : v.area.areaTag, name : v.area.name, @@ -162,7 +163,7 @@ MessageAreaListModule.prototype.mciReady = function(mciData, cb) { i = 1; areaListView.setFocusItems(_.map(self.messageAreas, v => { - return focusListFormat.format({ + return stringFormat(focusListFormat, { index : i++, areaTag : v.area.areaTag, name : v.area.name, diff --git a/mods/msg_area_view_fse.js b/mods/msg_area_view_fse.js index f857589f..a82433b2 100644 --- a/mods/msg_area_view_fse.js +++ b/mods/msg_area_view_fse.js @@ -122,4 +122,8 @@ AreaViewFSEModule.prototype.restoreSavedState = function(savedState) { this.messageList = savedState.messageList; this.messageIndex = savedState.messageIndex; this.messageTotal = savedState.messageTotal; -}; \ No newline at end of file +}; + +AreaViewFSEModule.prototype.getMenuResult = function() { + return this.messageIndex; +}; diff --git a/mods/msg_conf_list.js b/mods/msg_conf_list.js index 8f798284..1a328430 100644 --- a/mods/msg_conf_list.js +++ b/mods/msg_conf_list.js @@ -8,6 +8,7 @@ const messageArea = require('../core/message_area.js'); const displayThemeArt = require('../core/theme.js').displayThemeArt; const displayThemedPause = require('../core/theme.js').displayThemedPause; const resetScreen = require('../core/ansi_term.js').resetScreen; +const stringFormat = require('../core/string_format.js'); // deps const async = require('async'); @@ -121,7 +122,7 @@ MessageConfListModule.prototype.mciReady = function(mciData, cb) { const confListView = vc.getView(MCICodeIDs.ConfList); let i = 1; confListView.setItems(_.map(self.messageConfs, v => { - return listFormat.format({ + return stringFormat(listFormat, { index : i++, confTag : v.conf.confTag, name : v.conf.name, @@ -131,7 +132,7 @@ MessageConfListModule.prototype.mciReady = function(mciData, cb) { i = 1; confListView.setFocusItems(_.map(self.messageConfs, v => { - return focusListFormat.format({ + return stringFormat(focusListFormat, { index : i++, confTag : v.conf.confTag, name : v.conf.name, diff --git a/mods/msg_list.js b/mods/msg_list.js index e397c52c..3a36052a 100644 --- a/mods/msg_list.js +++ b/mods/msg_list.js @@ -5,6 +5,7 @@ const MenuModule = require('../core/menu_module.js').MenuModule; const ViewController = require('../core/view_controller.js').ViewController; const messageArea = require('../core/message_area.js'); +const stringFormat = require('../core/string_format.js'); // deps const async = require('async'); @@ -209,11 +210,11 @@ MessageListModule.prototype.mciReady = function(mciData, cb) { // which items are requested (e.g. their format at least) *as-needed* vs trying to get the format for all of them at once msgListView.setItems(_.map(self.messageList, listEntry => { - return listFormat.format(listEntry); + return stringFormat(listFormat, listEntry); })); msgListView.setFocusItems(_.map(self.messageList, listEntry => { - return focusListFormat.format(listEntry); + return stringFormat(focusListFormat, listEntry); })); msgListView.on('index update', function indexUpdated(idx) { diff --git a/mods/onelinerz.js b/mods/onelinerz.js index fd7467e2..a00685f2 100644 --- a/mods/onelinerz.js +++ b/mods/onelinerz.js @@ -154,7 +154,6 @@ function OnelinerzModule(options) { } ); })); - entriesView.focusItems = entriesView.items; // :TODO: this is a hack entriesView.redraw(); return callback(null); diff --git a/mods/rumorz.js b/mods/rumorz.js index 45656ddf..20aace03 100644 --- a/mods/rumorz.js +++ b/mods/rumorz.js @@ -8,6 +8,7 @@ const theme = require('../core/theme.js'); const resetScreen = require('../core/ansi_term.js').resetScreen; const StatLog = require('../core/stat_log.js'); const renderStringLength = require('../core/string_util.js').renderStringLength; +const stringFormat = require('../core/string_format.js'); // deps const async = require('async'); @@ -158,8 +159,8 @@ exports.getModule = class RumorzModule extends MenuModule { const listFormat = config.listFormat || '{rumor}'; const focusListFormat = config.focusListFormat || listFormat; - entriesView.setItems(entries.map( e => listFormat.format( { rumor : e.log_value } ) ) ); - entriesView.setFocusItems(entries.map(e => focusListFormat.format( { rumor : e.log_value } ) ) ); + entriesView.setItems(entries.map( e => stringFormat(listFormat, { rumor : e.log_value } ) ) ); + entriesView.setFocusItems(entries.map(e => stringFormat(focusListFormat, { rumor : e.log_value } ) ) ); entriesView.redraw(); return callback(null); diff --git a/mods/themes/luciano_blocktronics/NEWMSGS.ANS b/mods/themes/luciano_blocktronics/NEWMSGS.ANS index 911f1f20..5a58161e 100644 Binary files a/mods/themes/luciano_blocktronics/NEWMSGS.ANS and b/mods/themes/luciano_blocktronics/NEWMSGS.ANS differ diff --git a/mods/user_list.js b/mods/user_list.js index 5303e420..8401a182 100644 --- a/mods/user_list.js +++ b/mods/user_list.js @@ -5,10 +5,10 @@ var MenuModule = require('../core/menu_module.js').MenuModule; //var userDb = require('../core/database.js').dbs.user; var getUserList = require('../core/user.js').getUserList; var ViewController = require('../core/view_controller.js').ViewController; +const stringFormat = require('../core/string_format.js'); var moment = require('moment'); var async = require('async'); -var assert = require('assert'); var _ = require('lodash'); /* @@ -92,11 +92,11 @@ UserListModule.prototype.mciReady = function(mciData, cb) { } userListView.setItems(_.map(userList, function formatUserEntry(ue) { - return listFormat.format(getUserFmtObj(ue)); + return stringFormat(listFormat, getUserFmtObj(ue)); })); userListView.setFocusItems(_.map(userList, function formatUserEntry(ue) { - return focusListFormat.format(getUserFmtObj(ue)); + return stringFormat(focusListFormat, getUserFmtObj(ue)); })); userListView.redraw(); diff --git a/mods/whos_online.js b/mods/whos_online.js index 86cde07a..71db4f00 100644 --- a/mods/whos_online.js +++ b/mods/whos_online.js @@ -5,6 +5,7 @@ const MenuModule = require('../core/menu_module.js').MenuModule; const ViewController = require('../core/view_controller.js').ViewController; const getActiveNodeList = require('../core/client_connections.js').getActiveNodeList; +const stringFormat = require('../core/string_format.js'); // deps const async = require('async'); @@ -63,7 +64,7 @@ WhosOnlineModule.prototype.mciReady = function(mciData, cb) { }); oe.userName = nonAuthUser; } - return listFormat.format(oe); + return stringFormat(listFormat, oe); })); onlineListView.focusItems = onlineListView.items; diff --git a/package.json b/package.json index 5664f664..c0809674 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,7 @@ "node-uuid": "^1.4.7", "ptyw.js": "^0.3.7", "sqlite3": "^3.1.1", - "ssh2": "^0.4.13", - "string-format": "davidchambers/string-format#mini-language", + "ssh2": "^0.4.13", "temp": "^0.8.3", "inquirer" : "^1.1.0", "fs-extra" : "0.26.x",