Merge branch 'master' of ssh://numinibsd/git/base/enigma-bbs

This commit is contained in:
Bryan Ashby 2016-09-04 21:37:05 -06:00
commit ab596842d6
28 changed files with 217 additions and 200 deletions

View File

@ -2,15 +2,27 @@
'use strict'; 'use strict';
// //
// ANSI Terminal Support // ANSI Terminal Support Resources
// //
// Resources: // ANSI-BBS
// * http://ansi-bbs.org/ // * 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://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://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 // * http://www.inwap.com/pdp10/ansicode.txt
// //
// Other Implementations
// * https://github.com/chjj/term.js/blob/master/src/term.js
// ENiGMA½ // ENiGMA½
const miscUtil = require('./misc_util.js'); const miscUtil = require('./misc_util.js');

View File

@ -3,6 +3,7 @@
// ENiGMA½ // ENiGMA½
const Config = require('./config.js').config; const Config = require('./config.js').config;
const stringFormat = require('./string_format.js');
// base/modules // base/modules
const fs = require('fs'); const fs = require('fs');
@ -124,7 +125,7 @@ module.exports = class ArchiveUtil {
let args = _.clone(archiver.compressArgs); // don't muck with orig let args = _.clone(archiver.compressArgs); // don't muck with orig
for(let i = 0; i < args.length; ++i) { for(let i = 0; i < args.length; ++i) {
args[i] = args[i].format({ args[i] = stringFormat(args[i], {
archivePath : archivePath, archivePath : archivePath,
fileList : files.join(' '), fileList : files.join(' '),
}); });
@ -144,7 +145,7 @@ module.exports = class ArchiveUtil {
let args = _.clone(archiver.decompressArgs); // don't muck with orig let args = _.clone(archiver.decompressArgs); // don't muck with orig
for(let i = 0; i < args.length; ++i) { for(let i = 0; i < args.length; ++i) {
args[i] = args[i].format({ args[i] = stringFormat(args[i], {
archivePath : archivePath, archivePath : archivePath,
extractPath : extractPath, extractPath : extractPath,
}); });

View File

@ -128,10 +128,10 @@ function initialize(cb) {
if(err) { if(err) {
console.error('Could not create path: ' + conf.config.paths[pathKey] + ': ' + err.toString()); console.error('Could not create path: ' + conf.config.paths[pathKey] + ': ' + err.toString());
} }
next(err); return next(err);
}); });
}, function dirCreationComplete(err) { }, function dirCreationComplete(err) {
callback(err); return callback(err);
}); });
}, },
function basicInit(callback) { function basicInit(callback) {
@ -142,22 +142,19 @@ function initialize(cb) {
process.on('SIGINT', shutdownSystem); process.on('SIGINT', shutdownSystem);
// Init some extensions return callback(null);
require('string-format').extend(String.prototype, require('./string_util.js').stringFormatExtensions);
callback(null);
}, },
function initDatabases(callback) { function initDatabases(callback) {
database.initializeDatabases(callback); return database.initializeDatabases(callback);
}, },
function initStatLog(callback) { function initStatLog(callback) {
require('./stat_log.js').init(callback); return require('./stat_log.js').init(callback);
}, },
function initThemes(callback) { function initThemes(callback) {
// Have to pull in here so it's after Config init // Have to pull in here so it's after Config init
require('./theme.js').initAvailableThemes(function onThemesInit(err, themeCount) { require('./theme.js').initAvailableThemes(function onThemesInit(err, themeCount) {
logger.log.info({ themeCount : themeCount }, 'Themes initialized'); logger.log.info({ themeCount : themeCount }, 'Themes initialized');
callback(err); return callback(err);
}); });
}, },
function loadSysOpInformation(callback) { function loadSysOpInformation(callback) {
@ -204,10 +201,10 @@ function initialize(cb) {
); );
}, },
function initMCI(callback) { function initMCI(callback) {
require('./predefined_mci.js').init(callback); return require('./predefined_mci.js').init(callback);
}, },
function readyMessageNetworkSupport(callback) { function readyMessageNetworkSupport(callback) {
require('./msg_network.js').startup(callback); return require('./msg_network.js').startup(callback);
}, },
function readyEventScheduler(callback) { function readyEventScheduler(callback) {
const EventSchedulerModule = require('./event_scheduler.js').EventSchedulerModule; const EventSchedulerModule = require('./event_scheduler.js').EventSchedulerModule;
@ -218,7 +215,7 @@ function initialize(cb) {
} }
], ],
function onComplete(err) { function onComplete(err) {
cb(err); return cb(err);
} }
); );
} }

View File

@ -292,7 +292,17 @@ function getDefaultConfig() {
}, },
logging : { 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 : { debug : {

View File

@ -1,6 +1,9 @@
/* jslint node: true */ /* jslint node: true */
'use strict'; 'use strict';
const stringFormat = require('./string_format.js');
const events = require('events'); const events = require('events');
const _ = require('lodash'); const _ = require('lodash');
const pty = require('ptyw.js'); 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 let args = _.clone(self.exeInfo.args); // we need a copy so the original is not modified
for(let i = 0; i < args.length; ++i) { 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, dropFile : self.exeInfo.dropFile,
node : self.exeInfo.node.toString(), node : self.exeInfo.node.toString(),
srvPort : sockServer ? sockServer.address().port.toString() : '-1', srvPort : sockServer ? sockServer.address().port.toString() : '-1',

View File

@ -2,17 +2,16 @@
'use strict'; 'use strict';
// ENiGMA½ // ENiGMA½
const MenuModule = require('../core/menu_module.js').MenuModule; const MenuModule = require('./menu_module.js').MenuModule;
const ViewController = require('../core/view_controller.js').ViewController; const ViewController = require('./view_controller.js').ViewController;
const ansi = require('../core/ansi_term.js'); const ansi = require('./ansi_term.js');
const theme = require('../core/theme.js'); const theme = require('./theme.js');
const Message = require('../core/message.js'); const Message = require('./message.js');
const getMessageAreaByTag = require('../core/message_area.js').getMessageAreaByTag; const updateMessageAreaLastReadId = require('./message_area.js').updateMessageAreaLastReadId;
const updateMessageAreaLastReadId = require('../core/message_area.js').updateMessageAreaLastReadId; const getUserIdAndName = require('./user.js').getUserIdAndName;
const getUserIdAndName = require('../core/user.js').getUserIdAndName; const cleanControlCodes = require('./string_util.js').cleanControlCodes;
const cleanControlCodes = require('../core/string_util.js').cleanControlCodes;
const StatLog = require('./stat_log.js'); const StatLog = require('./stat_log.js');
const stringFormat = require('./string_format.js');
// deps // deps
const async = require('async'); 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 = { this.menuMethods = {
// //
// Validation stuff // Validation stuff
@ -917,14 +931,7 @@ function FullScreenEditorModule(options) {
if(self.newQuoteBlock) { if(self.newQuoteBlock) {
self.newQuoteBlock = false; self.newQuoteBlock = false;
quoteMsgView.addText(self.getQuoteByHeader());
// :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)
);
} }
var quoteText = self.viewControllers.quoteBuilder.getView(3).getItem(formData.value.quote); var quoteText = self.viewControllers.quoteBuilder.getView(3).getItem(formData.value.quote);

View File

@ -1,63 +1,74 @@
/* jslint node: true */ /* jslint node: true */
'use strict'; 'use strict';
var bunyan = require('bunyan'); // deps
var paths = require('path'); const bunyan = require('bunyan');
var fs = require('fs'); const paths = require('path');
const fs = require('fs');
const _ = require('lodash');
module.exports = { module.exports = class Log {
init : function() {
var Config = require('./config.js').config;
//var ringBufferLimit = miscUtil.valueWithDefault(config.logRingBufferLimit, 100);
var logPath = Config.paths.logs;
// static init() {
// Create something a bit more friendly if the log directory cannot be used const Config = require('./config.js').config;
// const logPath = Config.paths.logs;
// :TODO: this seems cheesy...
var logPathError; const err = this.checkLogPath(logPath);
try { if(err) {
var pathStat = fs.statSync(logPath); console.error(err.message); // eslint-disable-line no-console
if(!pathStat.isDirectory()) { return process.exit();
logPathError = logPath + ' is not a directory!';
}
} catch(e) {
if('ENOENT' === e.code) {
logPathError = 'No such file or directory: ' + logPath;
} else {
logPathError = e.message;
}
} }
if(logPathError) { const logStreams = [];
console.error(logPathError); if(_.isObject(Config.logging.rotatingFile)) {
process.exit(); 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 -- // try to remove sensitive info by default, e.g. 'password' fields
// user should be able to configure rotations, levels to file vs ringBuffer, [ 'formData', 'formValue' ].forEach(keyName => {
// completely disable logging, etc. serializers[keyName] = (fd) => Log.hideSensitive(fd);
});
this.log = bunyan.createLogger({ this.log = bunyan.createLogger({
name : 'ENiGMA½ BBS', name : 'ENiGMA½ BBS',
streams : [ streams : logStreams,
{ serializers : serializers,
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.
}); });
} }
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 {};
}
}
}; };

View File

@ -66,7 +66,7 @@ var SPECIAL_KEY_MAP_DEFAULT = {
'line feed' : [ 'return' ], 'line feed' : [ 'return' ],
exit : [ 'esc' ], exit : [ 'esc' ],
backspace : [ 'backspace' ], backspace : [ 'backspace' ],
'delete' : [ 'del' ], delete : [ 'del' ],
tab : [ 'tab' ], tab : [ 'tab' ],
up : [ 'up arrow' ], up : [ 'up arrow' ],
down : [ 'down arrow' ], down : [ 'down arrow' ],
@ -802,7 +802,6 @@ function MultiLineEditTextView(options) {
self.emitEditPosition(); self.emitEditPosition();
}; };
//this.keyPressClearLine = function() {
this.keyPressDeleteLine = function() { this.keyPressDeleteLine = function() {
if(self.textLines.length > 0) { if(self.textLines.length > 0) {
self.removeCharactersFromText( self.removeCharactersFromText(

View File

@ -4,7 +4,8 @@
// ENiGMA½ // ENiGMA½
const msgArea = require('./message_area.js'); const msgArea = require('./message_area.js');
const MenuModule = require('./menu_module.js').MenuModule; 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 // deps
const _ = require('lodash'); const _ = require('lodash');
@ -121,15 +122,6 @@ function NewScanModule(options) {
const sortedAreas = msgArea.getSortedAvailMessageAreasByConfTag(conf.confTag, { client : self.client } ); const sortedAreas = msgArea.getSortedAvailMessageAreasByConfTag(conf.confTag, { client : self.client } );
const currentArea = sortedAreas[self.currentScanAux.area]; 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, // Scan and update index until we find something. If results are found,
// we'll goto the list module & show them. // we'll goto the list module & show them.
@ -147,7 +139,12 @@ function NewScanModule(options) {
} }
}, },
function updateStatusScanStarted(callback) { 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); return callback(null);
}, },
function getNewMessagesCountInArea(callback) { function getNewMessagesCountInArea(callback) {

View File

@ -9,6 +9,7 @@ var ServerModule = require('../server_module.js').ServerModule;
var userLogin = require('../user_login.js').userLogin; var userLogin = require('../user_login.js').userLogin;
var enigVersion = require('../../package.json').version; var enigVersion = require('../../package.json').version;
var theme = require('../theme.js'); var theme = require('../theme.js');
const stringFormat = require('../string_format.js');
var ssh2 = require('ssh2'); var ssh2 = require('ssh2');
var fs = require('fs'); var fs = require('fs');
@ -106,11 +107,11 @@ function SSHClient(clientConn) {
if(err) { if(err) {
interactivePrompt.prompt = 'Access denied\n' + ctx.username + '\'s password: '; interactivePrompt.prompt = 'Access denied\n' + ctx.username + '\'s password: ';
} else { } else {
var newUserNameList = '"' + (Config.users.newUserNames || []).join(', ') + '"'; const newUserNameList = _.has(Config, 'users.newUserNames') && Config.users.newUserNames.length > 0 ?
interactivePrompt.prompt = Config.users.newUserNames.map(newName => '"' + newName + '"').join(', ') :
'Access denied\n' + '(No new user names enabled!)';
artInfo.data.format( { newUserNames : newUserNameList } ) +
'\n' + ctx.username + '\'s password: '; interactivePrompt.prompt = `Access denied\n${stringFormat(artInfo.data, { newUserNames : newUserNameList })}\n${ctx.username}'s password'`;
} }
return ctx.prompt(interactivePrompt, retryPrompt); return ctx.prompt(interactivePrompt, retryPrompt);
}); });

View File

@ -4,6 +4,8 @@
const EnigError = require('./enig_error.js').EnigError; const EnigError = require('./enig_error.js').EnigError;
const pad = require('./string_util.js').pad; const pad = require('./string_util.js').pad;
const stylizeString = require('./string_util.js').stylizeString; const stylizeString = require('./string_util.js').stylizeString;
const renderStringLength = require('./string_util.js').renderStringLength;
const renderSubstr = require('./string_util.js').renderSubstr;
// deps // deps
const _ = require('lodash'); const _ = require('lodash');
@ -124,7 +126,7 @@ function getPadAlign(align) {
function formatString(value, tokens) { function formatString(value, tokens) {
const fill = tokens.fill || (tokens['0'] ? '0' : ' '); const fill = tokens.fill || (tokens['0'] ? '0' : ' ');
const align = tokens.align || (tokens['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) { if('' !== tokens.type && 's' !== tokens.type) {
throw new ValueError(`Unknown format code "${tokens.type}" for String object`); 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'); 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 = { const FormatNumRegExp = {
@ -167,7 +169,10 @@ function formatNumberHelper(n, precision, type) {
case 'x' : return n.toString(16); case 'x' : return n.toString(16);
case 'e' : return n.toExponential(precision).replace(FormatNumRegExp.ExponentRep, '$&0'); case 'e' : return n.toExponential(precision).replace(FormatNumRegExp.ExponentRep, '$&0');
case 'f' : return n.toFixed(precision); 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 * 100, precision, 'f') + '%';
case '' : return formatNumberHelper(n, precision, 'd'); case '' : return formatNumberHelper(n, precision, 'd');
@ -276,7 +281,7 @@ const REGEXP_BASIC_FORMAT = /{([^.!:}]+(?:\.[^.!:}]+)*)(?:\!([^:}]+))?(?:\:([^}]
function getValue(obj, path) { function getValue(obj, path) {
const value = _.get(obj, path); const value = _.get(obj, path);
if(value) { if(!_.isUndefined(value)) {
return _.isFunction(value) ? value() : value; return _.isFunction(value) ? value() : value;
} }
@ -286,9 +291,16 @@ function getValue(obj, path) {
module.exports = function format(fmt, obj) { module.exports = function format(fmt, obj) {
const re = REGEXP_BASIC_FORMAT; const re = REGEXP_BASIC_FORMAT;
let match; let match;
let pos; let pos;
let out = ''; let out = '';
let objPath ;
let transformer;
let formatSpec;
let value;
let tokens;
do { do {
pos = re.lastIndex; pos = re.lastIndex;
match = re.exec(fmt); match = re.exec(fmt);
@ -298,16 +310,16 @@ module.exports = function format(fmt, obj) {
out += fmt.slice(pos, match.index); out += fmt.slice(pos, match.index);
} }
const objPath = match[1]; objPath = match[1];
const transformer = match[2]; transformer = match[2];
const formatSpec = match[3]; formatSpec = match[3];
let value = getValue(obj, objPath); value = getValue(obj, objPath);
if(transformer) { if(transformer) {
value = transformValue(transformer, value); value = transformValue(transformer, value);
} }
const tokens = tokenizeFormatSpec(formatSpec || ''); tokens = tokenizeFormatSpec(formatSpec || '');
if(!isNaN(parseInt(value))) { if(!isNaN(parseInt(value))) {
out += formatNumber(value, tokens); out += formatNumber(value, tokens);

View File

@ -195,45 +195,6 @@ function stringFromNullTermBuffer(buf, encoding) {
return iconv.decode(buf.slice(0, nullPos), encoding || 'utf-8'); 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 // :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 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; 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) { function renderSubstr(str, start, length) {
start = start || 0; start = start || 0;
length = length || str.length - start; length = Math.max(0, (length || str.length - start) - 1);
const re = ANSI_REGEXP; const re = ANSI_REGEXP;
let pos; let pos;

View File

@ -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() { TextView.prototype.clearText = function() {
this.setText(''); this.setText('');
}; };

View File

@ -16,7 +16,7 @@ exports.userLogin = userLogin;
function userLogin(client, username, password, cb) { function userLogin(client, username, password, cb) {
client.user.authenticate(username, password, function authenticated(err) { client.user.authenticate(username, password, function authenticated(err) {
if(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: if username exists, record failed login attempt to properties
// :TODO: check Config max failed logon attempts/etc. - set err.maxAttempts = true // :TODO: check Config max failed logon attempts/etc. - set err.maxAttempts = true

View File

@ -6,6 +6,7 @@ var MCIViewFactory = require('./mci_view_factory.js').MCIViewFactory;
var menuUtil = require('./menu_util.js'); var menuUtil = require('./menu_util.js');
var asset = require('./asset.js'); var asset = require('./asset.js');
var ansi = require('./ansi_term.js'); var ansi = require('./ansi_term.js');
const Log = require('./logger.js');
// deps // deps
var events = require('events'); 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; return true;
}; };

View File

@ -8,6 +8,7 @@ const ViewController = require('../core/view_controller.js').ViewController;
const ansi = require('../core/ansi_term.js'); const ansi = require('../core/ansi_term.js');
const theme = require('../core/theme.js'); const theme = require('../core/theme.js');
const getUserName = require('../core/user.js').getUserName; const getUserName = require('../core/user.js').getUserName;
const stringFormat = require('../core/string_format.js');
// deps // deps
const async = require('async'); const async = require('async');
@ -99,7 +100,6 @@ function BBSListModule(options) {
self.setViewText(MciViewIds.view[mciName], ''); self.setViewText(MciViewIds.view[mciName], '');
}); });
} else { } else {
// :TODO: we really need pipe code support for TextView!!
const youSubmittedFormat = config.youSubmittedFormat || '{submitter} (You!)'; const youSubmittedFormat = config.youSubmittedFormat || '{submitter} (You!)';
Object.keys(SELECTED_MCI_NAME_TO_ENTRY).forEach(mciName => { Object.keys(SELECTED_MCI_NAME_TO_ENTRY).forEach(mciName => {
@ -107,7 +107,7 @@ function BBSListModule(options) {
if(MciViewIds.view[mciName]) { if(MciViewIds.view[mciName]) {
if('SelectedBBSSubmitter' == mciName && entry.submitterUserId == self.client.user.userId) { 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 { } else {
self.setViewText(MciViewIds.view[mciName], t); self.setViewText(MciViewIds.view[mciName], t);
} }
@ -120,8 +120,8 @@ function BBSListModule(options) {
const listFormat = config.listFormat || '{bbsName}'; const listFormat = config.listFormat || '{bbsName}';
const focusListFormat = config.focusListFormat || '{bbsName}'; const focusListFormat = config.focusListFormat || '{bbsName}';
entriesView.setItems(self.entries.map( e => listFormat.format(e) ) ); entriesView.setItems(self.entries.map( e => stringFormat(listFormat, e) ) );
entriesView.setFocusItems(self.entries.map( e => focusListFormat.format(e) ) ); entriesView.setFocusItems(self.entries.map( e => stringFormat(focusListFormat, e) ) );
}; };
this.displayBBSList = function(clearScreen, cb) { this.displayBBSList = function(clearScreen, cb) {

View File

@ -2,6 +2,7 @@
'use strict'; 'use strict';
var MenuModule = require('../core/menu_module.js').MenuModule; var MenuModule = require('../core/menu_module.js').MenuModule;
const stringFormat = require('../core/string_format.js');
// deps // deps
const async = require('async'); const async = require('async');
@ -86,10 +87,10 @@ function ErcClientModule(options) {
try { try {
if(data.userName) { if(data.userName) {
// user message // user message
text = self.chatEntryFormat.format(data); text = stringFormat(self.chatEntryFormat, data);
} else { } else {
// system message // system message
text = self.systemEntryFormat.format(data); text = stringFormat(self.systemEntryFormat, data);
} }
} catch(e) { } catch(e) {
return self.client.log.warn( { error : e.message }, 'ERC: chatEntryFormat error'); return self.client.log.warn( { error : e.message }, 'ERC: chatEntryFormat error');

View File

@ -8,6 +8,7 @@ const StatLog = require('../core/stat_log.js');
const getUserName = require('../core/user.js').getUserName; const getUserName = require('../core/user.js').getUserName;
const loadProperties = require('../core/user.js').loadProperties; const loadProperties = require('../core/user.js').loadProperties;
const isRootUserId = require('../core/user.js').isRootUserId; const isRootUserId = require('../core/user.js').isRootUserId;
const stringFormat = require('../core/string_format.js');
// deps // deps
const moment = require('moment'); const moment = require('moment');
@ -123,12 +124,9 @@ LastCallersModule.prototype.mciReady = function(mciData, cb) {
); );
}, },
function populateList(callback) { 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) ) ); callersView.setItems(_.map(loginHistory, ce => stringFormat(listFormat, ce) ) );
// :TODO: This is a hack until pipe codes are better implemented
callersView.focusItems = callersView.items;
callersView.redraw(); callersView.redraw();
return callback(null); return callback(null);

View File

@ -8,6 +8,7 @@ const messageArea = require('../core/message_area.js');
const displayThemeArt = require('../core/theme.js').displayThemeArt; const displayThemeArt = require('../core/theme.js').displayThemeArt;
const displayThemedPause = require('../core/theme.js').displayThemedPause; const displayThemedPause = require('../core/theme.js').displayThemedPause;
const resetScreen = require('../core/ansi_term.js').resetScreen; const resetScreen = require('../core/ansi_term.js').resetScreen;
const stringFormat = require('../core/string_format.js');
// deps // deps
const async = require('async'); const async = require('async');
@ -152,7 +153,7 @@ MessageAreaListModule.prototype.mciReady = function(mciData, cb) {
const areaListView = vc.getView(MCICodesIDs.AreaList); const areaListView = vc.getView(MCICodesIDs.AreaList);
let i = 1; let i = 1;
areaListView.setItems(_.map(self.messageAreas, v => { areaListView.setItems(_.map(self.messageAreas, v => {
return listFormat.format({ return stringFormat(listFormat, {
index : i++, index : i++,
areaTag : v.area.areaTag, areaTag : v.area.areaTag,
name : v.area.name, name : v.area.name,
@ -162,7 +163,7 @@ MessageAreaListModule.prototype.mciReady = function(mciData, cb) {
i = 1; i = 1;
areaListView.setFocusItems(_.map(self.messageAreas, v => { areaListView.setFocusItems(_.map(self.messageAreas, v => {
return focusListFormat.format({ return stringFormat(focusListFormat, {
index : i++, index : i++,
areaTag : v.area.areaTag, areaTag : v.area.areaTag,
name : v.area.name, name : v.area.name,

View File

@ -123,3 +123,7 @@ AreaViewFSEModule.prototype.restoreSavedState = function(savedState) {
this.messageIndex = savedState.messageIndex; this.messageIndex = savedState.messageIndex;
this.messageTotal = savedState.messageTotal; this.messageTotal = savedState.messageTotal;
}; };
AreaViewFSEModule.prototype.getMenuResult = function() {
return this.messageIndex;
};

View File

@ -8,6 +8,7 @@ const messageArea = require('../core/message_area.js');
const displayThemeArt = require('../core/theme.js').displayThemeArt; const displayThemeArt = require('../core/theme.js').displayThemeArt;
const displayThemedPause = require('../core/theme.js').displayThemedPause; const displayThemedPause = require('../core/theme.js').displayThemedPause;
const resetScreen = require('../core/ansi_term.js').resetScreen; const resetScreen = require('../core/ansi_term.js').resetScreen;
const stringFormat = require('../core/string_format.js');
// deps // deps
const async = require('async'); const async = require('async');
@ -121,7 +122,7 @@ MessageConfListModule.prototype.mciReady = function(mciData, cb) {
const confListView = vc.getView(MCICodeIDs.ConfList); const confListView = vc.getView(MCICodeIDs.ConfList);
let i = 1; let i = 1;
confListView.setItems(_.map(self.messageConfs, v => { confListView.setItems(_.map(self.messageConfs, v => {
return listFormat.format({ return stringFormat(listFormat, {
index : i++, index : i++,
confTag : v.conf.confTag, confTag : v.conf.confTag,
name : v.conf.name, name : v.conf.name,
@ -131,7 +132,7 @@ MessageConfListModule.prototype.mciReady = function(mciData, cb) {
i = 1; i = 1;
confListView.setFocusItems(_.map(self.messageConfs, v => { confListView.setFocusItems(_.map(self.messageConfs, v => {
return focusListFormat.format({ return stringFormat(focusListFormat, {
index : i++, index : i++,
confTag : v.conf.confTag, confTag : v.conf.confTag,
name : v.conf.name, name : v.conf.name,

View File

@ -5,6 +5,7 @@
const MenuModule = require('../core/menu_module.js').MenuModule; const MenuModule = require('../core/menu_module.js').MenuModule;
const ViewController = require('../core/view_controller.js').ViewController; const ViewController = require('../core/view_controller.js').ViewController;
const messageArea = require('../core/message_area.js'); const messageArea = require('../core/message_area.js');
const stringFormat = require('../core/string_format.js');
// deps // deps
const async = require('async'); 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 // 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 => { msgListView.setItems(_.map(self.messageList, listEntry => {
return listFormat.format(listEntry); return stringFormat(listFormat, listEntry);
})); }));
msgListView.setFocusItems(_.map(self.messageList, listEntry => { msgListView.setFocusItems(_.map(self.messageList, listEntry => {
return focusListFormat.format(listEntry); return stringFormat(focusListFormat, listEntry);
})); }));
msgListView.on('index update', function indexUpdated(idx) { msgListView.on('index update', function indexUpdated(idx) {

View File

@ -154,7 +154,6 @@ function OnelinerzModule(options) {
} ); } );
})); }));
entriesView.focusItems = entriesView.items; // :TODO: this is a hack
entriesView.redraw(); entriesView.redraw();
return callback(null); return callback(null);

View File

@ -8,6 +8,7 @@ const theme = require('../core/theme.js');
const resetScreen = require('../core/ansi_term.js').resetScreen; const resetScreen = require('../core/ansi_term.js').resetScreen;
const StatLog = require('../core/stat_log.js'); const StatLog = require('../core/stat_log.js');
const renderStringLength = require('../core/string_util.js').renderStringLength; const renderStringLength = require('../core/string_util.js').renderStringLength;
const stringFormat = require('../core/string_format.js');
// deps // deps
const async = require('async'); const async = require('async');
@ -158,8 +159,8 @@ exports.getModule = class RumorzModule extends MenuModule {
const listFormat = config.listFormat || '{rumor}'; const listFormat = config.listFormat || '{rumor}';
const focusListFormat = config.focusListFormat || listFormat; const focusListFormat = config.focusListFormat || listFormat;
entriesView.setItems(entries.map( e => listFormat.format( { rumor : e.log_value } ) ) ); entriesView.setItems(entries.map( e => stringFormat(listFormat, { rumor : e.log_value } ) ) );
entriesView.setFocusItems(entries.map(e => focusListFormat.format( { rumor : e.log_value } ) ) ); entriesView.setFocusItems(entries.map(e => stringFormat(focusListFormat, { rumor : e.log_value } ) ) );
entriesView.redraw(); entriesView.redraw();
return callback(null); return callback(null);

View File

@ -5,10 +5,10 @@ var MenuModule = require('../core/menu_module.js').MenuModule;
//var userDb = require('../core/database.js').dbs.user; //var userDb = require('../core/database.js').dbs.user;
var getUserList = require('../core/user.js').getUserList; var getUserList = require('../core/user.js').getUserList;
var ViewController = require('../core/view_controller.js').ViewController; var ViewController = require('../core/view_controller.js').ViewController;
const stringFormat = require('../core/string_format.js');
var moment = require('moment'); var moment = require('moment');
var async = require('async'); var async = require('async');
var assert = require('assert');
var _ = require('lodash'); var _ = require('lodash');
/* /*
@ -92,11 +92,11 @@ UserListModule.prototype.mciReady = function(mciData, cb) {
} }
userListView.setItems(_.map(userList, function formatUserEntry(ue) { userListView.setItems(_.map(userList, function formatUserEntry(ue) {
return listFormat.format(getUserFmtObj(ue)); return stringFormat(listFormat, getUserFmtObj(ue));
})); }));
userListView.setFocusItems(_.map(userList, function formatUserEntry(ue) { userListView.setFocusItems(_.map(userList, function formatUserEntry(ue) {
return focusListFormat.format(getUserFmtObj(ue)); return stringFormat(focusListFormat, getUserFmtObj(ue));
})); }));
userListView.redraw(); userListView.redraw();

View File

@ -5,6 +5,7 @@
const MenuModule = require('../core/menu_module.js').MenuModule; const MenuModule = require('../core/menu_module.js').MenuModule;
const ViewController = require('../core/view_controller.js').ViewController; const ViewController = require('../core/view_controller.js').ViewController;
const getActiveNodeList = require('../core/client_connections.js').getActiveNodeList; const getActiveNodeList = require('../core/client_connections.js').getActiveNodeList;
const stringFormat = require('../core/string_format.js');
// deps // deps
const async = require('async'); const async = require('async');
@ -63,7 +64,7 @@ WhosOnlineModule.prototype.mciReady = function(mciData, cb) {
}); });
oe.userName = nonAuthUser; oe.userName = nonAuthUser;
} }
return listFormat.format(oe); return stringFormat(listFormat, oe);
})); }));
onlineListView.focusItems = onlineListView.items; onlineListView.focusItems = onlineListView.items;

View File

@ -28,7 +28,6 @@
"ptyw.js": "^0.3.7", "ptyw.js": "^0.3.7",
"sqlite3": "^3.1.1", "sqlite3": "^3.1.1",
"ssh2": "^0.4.13", "ssh2": "^0.4.13",
"string-format": "davidchambers/string-format#mini-language",
"temp": "^0.8.3", "temp": "^0.8.3",
"inquirer" : "^1.1.0", "inquirer" : "^1.1.0",
"fs-extra" : "0.26.x", "fs-extra" : "0.26.x",