* Code cleanup and eslint since -- remove unused variables, clean up RegExs, so on...

This commit is contained in:
Bryan Ashby 2018-01-15 12:22:11 -07:00
parent a106050ba3
commit ac1433e84b
112 changed files with 1375 additions and 1898 deletions

View File

@ -87,11 +87,11 @@ exports.getModule = class AbracadabraModule extends MenuModule {
[
function validateNodeCount(callback) {
if(self.config.nodeMax > 0 &&
_.isNumber(activeDoorNodeInstances[self.config.name]) &&
_.isNumber(activeDoorNodeInstances[self.config.name]) &&
activeDoorNodeInstances[self.config.name] + 1 > self.config.nodeMax)
{
self.client.log.info(
{
self.client.log.info(
{
name : self.config.name,
activeCount : activeDoorNodeInstances[self.config.name]
},
@ -118,11 +118,11 @@ exports.getModule = class AbracadabraModule extends MenuModule {
} else {
activeDoorNodeInstances[self.config.name] = 1;
}
callback(null);
}
},
function generateDropfile(callback) {
function generateDropfile(callback) {
self.dropFile = new DropFile(self.client, self.config.dropFileType);
var fullPath = self.dropFile.fullPath;

View File

@ -13,7 +13,7 @@ class ACS {
constructor(client) {
this.client = client;
}
check(acs, scope, defaultAcs) {
acs = acs ? acs[scope] : defaultAcs;
acs = acs || defaultAcs;
@ -22,7 +22,7 @@ class ACS {
} catch(e) {
Log.warn( { exception : e, acs : acs }, 'Exception caught checking ACS');
return false;
}
}
}
//

View File

@ -3,7 +3,9 @@
const miscUtil = require('./misc_util.js');
const ansi = require('./ansi_term.js');
const Log = require('./logger.js').log;
// deps
const events = require('events');
const util = require('util');
const _ = require('lodash');
@ -24,7 +26,7 @@ function ANSIEscapeParser(options) {
this.graphicRendition = {};
this.parseState = {
re : /(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g,
re : /(?:\x1b\x5b)([?=;0-9]*?)([ABCDHJKfhlmnpsu])/g, // eslint-disable-line no-control-regex
};
options = miscUtil.valueWithDefault(options, {
@ -46,7 +48,7 @@ function ANSIEscapeParser(options) {
self.column = Math.max(self.column, 1);
self.column = Math.min(self.column, self.termWidth); // can't move past term width
self.row = Math.max(self.row, 1);
self.positionUpdated();
};
@ -63,7 +65,7 @@ function ANSIEscapeParser(options) {
delete self.savedPosition;
self.positionUpdated();
// self.rowUpdated();
// self.rowUpdated();
};
self.clearScreen = function() {
@ -71,7 +73,7 @@ function ANSIEscapeParser(options) {
self.emit('clear screen');
};
/*
/*
self.rowUpdated = function() {
self.emit('row update', self.row + self.scrollBack);
};*/
@ -95,7 +97,7 @@ function ANSIEscapeParser(options) {
start = pos;
self.column = 1;
self.positionUpdated();
break;
@ -132,7 +134,7 @@ function ANSIEscapeParser(options) {
if(self.column > self.termWidth) {
self.column = 1;
self.row += 1;
self.positionUpdated();
}
@ -142,17 +144,9 @@ function ANSIEscapeParser(options) {
}
}
function getProcessedMCI(mci) {
if(self.mciReplaceChar.length > 0) {
return ansi.getSGRFromGraphicRendition(self.graphicRendition, true) + new Array(mci.length + 1).join(self.mciReplaceChar);
} else {
return mci;
}
}
function parseMCI(buffer) {
// :TODO: move this to "constants" seciton @ top
var mciRe = /\%([A-Z]{2})([0-9]{1,2})?(?:\(([0-9A-Za-z,]+)\))*/g;
var mciRe = /%([A-Z]{2})([0-9]{1,2})?(?:\(([0-9A-Za-z,]+)\))*/g;
var pos = 0;
var match;
var mciCode;
@ -186,27 +180,23 @@ function ANSIEscapeParser(options) {
self.graphicRenditionForErase = _.clone(self.graphicRendition);
}
self.emit('mci', {
mci : mciCode,
self.emit('mci', {
mci : mciCode,
id : id ? parseInt(id, 10) : null,
args : args,
args : args,
SGR : ansi.getSGRFromGraphicRendition(self.graphicRendition, true)
});
if(self.mciReplaceChar.length > 0) {
const sgrCtrl = ansi.getSGRFromGraphicRendition(self.graphicRenditionForErase);
self.emit('control', sgrCtrl, 'm', sgrCtrl.slice(2).split(/[\;m]/).slice(0, 3));
self.emit('control', sgrCtrl, 'm', sgrCtrl.slice(2).split(/[;m]/).slice(0, 3));
literal(new Array(match[0].length + 1).join(self.mciReplaceChar));
} else {
literal(match[0]);
}
//literal(getProcessedMCI(match[0]));
//self.emit('chunk', getProcessedMCI(match[0]));
}
} while(0 !== mciRe.lastIndex);
@ -220,7 +210,7 @@ function ANSIEscapeParser(options) {
self.parseState = {
// ignore anything past EOF marker, if any
buffer : input.split(String.fromCharCode(0x1a), 1)[0],
re : /(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g,
re : /(?:\x1b\x5b)([?=;0-9]*?)([ABCDHJKfhlmnpsu])/g, // eslint-disable-line no-control-regex
stop : false,
};
};
@ -290,14 +280,14 @@ function ANSIEscapeParser(options) {
break;
}
}
parseMCI(lastBit)
parseMCI(lastBit);
}
self.emit('complete');
};
/*
/*
self.parse = function(buffer, savedRe) {
// :TODO: ensure this conforms to ANSI-BBS / CTerm / bansi.txt for movement/etc.
// :TODO: move this to "constants" section @ top
@ -382,12 +372,12 @@ function ANSIEscapeParser(options) {
break;
// save position
case 's' :
case 's' :
self.saveCursorPosition();
break;
// restore position
case 'u' :
case 'u' :
self.restoreCursorPosition();
break;
@ -422,7 +412,7 @@ function ANSIEscapeParser(options) {
case 1 :
case 2 :
case 22 :
case 22 :
self.graphicRendition.intensity = arg;
break;
@ -448,7 +438,7 @@ function ANSIEscapeParser(options) {
break;
default :
console.log('Unknown attribute: ' + arg); // :TODO: Log properly
Log.trace( { attribute : arg }, 'Unknown attribute while parsing ANSI');
break;
}
}

View File

@ -4,7 +4,7 @@
// ENiGMA½
const ANSIEscapeParser = require('./ansi_escape_parser.js').ANSIEscapeParser;
const ANSI = require('./ansi_term.js');
const {
const {
splitTextAtTerms,
renderStringLength
} = require('./string_util.js');
@ -41,7 +41,7 @@ module.exports = function ansiPrep(input, options, cb) {
if(canvas[row]) {
return;
}
canvas[row] = Array.from( { length : options.cols}, () => new Object() );
}
@ -113,17 +113,17 @@ module.exports = function ansiPrep(input, options, cb) {
const lastCol = getLastPopulatedColumn(row) + 1;
let i;
line = options.indent ?
line = options.indent ?
output.length > 0 ? ' '.repeat(options.indent) : '' :
'';
for(i = 0; i < lastCol; ++i) {
const col = row[i];
sgr = !options.asciiMode && 0 === i ?
sgr = !options.asciiMode && 0 === i ?
col.initialSgr ? ANSI.getSGRFromGraphicRendition(col.initialSgr) : '' :
'';
if(!options.asciiMode && col.sgr) {
sgr += ANSI.getSGRFromGraphicRendition(col.sgr);
}
@ -148,7 +148,7 @@ module.exports = function ansiPrep(input, options, cb) {
if(options.exportMode) {
//
// If we're in export mode, we do some additional hackery:
//
//
// * Hard wrap ALL lines at <= 79 *characters* (not visible columns)
// if a line must wrap early, we'll place a ESC[A ESC[<N>C where <N>
// represents chars to get back to the position we were previously at
@ -157,8 +157,8 @@ module.exports = function ansiPrep(input, options, cb) {
//
// :TODO: this would be better to do as part of the processing above, but this will do for now
const MAX_CHARS = 79 - 8; // 79 max, - 8 for max ESC seq's we may prefix a line with
let exportOutput = '';
let exportOutput = '';
let m;
let afterSeq;
let wantMore;
@ -184,7 +184,7 @@ module.exports = function ansiPrep(input, options, cb) {
splitAt = m.index;
wantMore = false; // can't eat up any more
}
break; // seq's beyond this point are >= MAX_CHARS
}
}
@ -203,7 +203,7 @@ module.exports = function ansiPrep(input, options, cb) {
exportOutput += `${part}\r\n`;
if(fullLine.length > 0) { // more to go for this line?
exportOutput += `${ANSI.up()}${ANSI.right(renderStart)}`;
exportOutput += `${ANSI.up()}${ANSI.right(renderStart)}`;
} else {
exportOutput += ANSI.up();
}

View File

@ -3,7 +3,7 @@
//
// ANSI Terminal Support Resources
//
//
// ANSI-BBS
// * http://ansi-bbs.org/
//
@ -31,7 +31,7 @@
// For a board, we need to support the semi-standard ANSI-BBS "spec" which
// is bastardized mix of DOS ANSI.SYS, cterm.txt, bansi.txt and a little other.
// This gives us NetRunner, SyncTERM, EtherTerm, most *nix terminals, compatibilitiy
// with legit oldschool DOS terminals, and so on.
// with legit oldschool DOS terminals, and so on.
//
// ENiGMA½
@ -113,7 +113,7 @@ const CONTROL = {
//
// Support:
// * SyncTERM: Works as expected
// * NetRunner:
// * NetRunner:
//
// General Notes:
// See also notes in bansi.txt and cterm.txt about the various
@ -160,7 +160,7 @@ const SGRValues = {
negative : 7,
hidden : 8,
normal : 22, //
normal : 22, //
steady : 25,
positive : 27,
@ -203,7 +203,7 @@ function getBGColorValue(name) {
// :TODO: Create mappings for aliases... maybe make this a map to values instead
// :TODO: Break this up in to two parts:
// 1) FONT_AND_CODE_PAGES (e.g. SyncTERM/cterm)
// 2) SAUCE_FONT_MAP: Sauce name(s) -> items in FONT_AND_CODE_PAGES.
// 2) SAUCE_FONT_MAP: Sauce name(s) -> items in FONT_AND_CODE_PAGES.
// ...we can then have getFontFromSAUCEName(sauceFontName)
// Also, create a SAUCE_ENCODING_MAP: SAUCE font name -> encodings
@ -215,45 +215,45 @@ function getBGColorValue(name) {
//
const SYNCTERM_FONT_AND_ENCODING_TABLE = [
'cp437',
'cp1251',
'koi8_r',
'iso8859_2',
'iso8859_4',
'cp866',
'iso8859_9',
'haik8',
'iso8859_8',
'koi8_u',
'iso8859_15',
'cp1251',
'koi8_r',
'iso8859_2',
'iso8859_4',
'koi8_r_b',
'iso8859_4',
'iso8859_5',
'ARMSCII_8',
'cp866',
'iso8859_9',
'haik8',
'iso8859_8',
'koi8_u',
'iso8859_15',
'cp850',
'cp850',
'cp885',
'cp1251',
'iso8859_7',
'koi8-r_c',
'iso8859_4',
'iso8859_1',
'cp866',
'cp437',
'cp866',
'iso8859_4',
'koi8_r_b',
'iso8859_4',
'iso8859_5',
'ARMSCII_8',
'iso8859_15',
'cp850',
'cp850',
'cp885',
'cp866_u',
'iso8859_1',
'cp1131',
'c64_upper',
'cp1251',
'iso8859_7',
'koi8-r_c',
'iso8859_4',
'iso8859_1',
'cp866',
'cp437',
'cp866',
'cp885',
'cp866_u',
'iso8859_1',
'cp1131',
'c64_upper',
'c64_lower',
'c128_upper',
'c128_lower',
'atari',
'pot_noodle',
'c128_upper',
'c128_lower',
'atari',
'pot_noodle',
'mo_soul',
'microknight_plus',
'microknight_plus',
'topaz_plus',
'microknight',
'topaz',
@ -289,7 +289,7 @@ const FONT_ALIAS_TO_SYNCTERM_MAP = {
'topaz' : 'topaz',
'amiga_topaz_1' : 'topaz',
'amiga_topaz_1+' : 'topaz_plus',
'topazplus' : 'topaz_plus',
'topazplus' : 'topaz_plus',
'topaz_plus' : 'topaz_plus',
'amiga_topaz_2' : 'topaz',
'amiga_topaz_2+' : 'topaz_plus',
@ -349,7 +349,7 @@ function setCursorStyle(cursorStyle) {
return `${ESC_CSI}${ps} q`;
}
return '';
}
// Create methods such as up(), nextLine(),...

View File

@ -23,7 +23,7 @@ class Archiver {
}
ok() {
return this.canCompress() && this.canDecompress();
return this.canCompress() && this.canDecompress();
}
can(what) {
@ -41,7 +41,7 @@ class Archiver {
}
module.exports = class ArchiveUtil {
constructor() {
this.archivers = {};
this.longestSignature = 0;
@ -93,7 +93,7 @@ module.exports = class ArchiveUtil {
getArchiver(mimeTypeOrExtension) {
mimeTypeOrExtension = resolveMimeType(mimeTypeOrExtension);
if(!mimeTypeOrExtension) { // lookup returns false on failure
return;
}
@ -103,21 +103,23 @@ module.exports = class ArchiveUtil {
return _.get( Config, [ 'archives', 'archivers', archiveHandler ] );
}
}
haveArchiver(archType) {
return this.getArchiver(archType) ? true : false;
}
detectTypeWithBuf(buf, cb) {
// :TODO: implement me!
// :TODO: implement me:
/*
detectTypeWithBuf(buf, cb) {
}
*/
detectType(path, cb) {
fs.open(path, 'r', (err, fd) => {
if(err) {
return cb(err);
}
const buf = new Buffer(this.longestSignature);
fs.read(fd, buf, 0, buf.length, 0, (err, bytesRead) => {
if(err) {
@ -140,7 +142,7 @@ module.exports = class ArchiveUtil {
});
return cb(archFormat ? null : Errors.General('Unknown type'), archFormat);
});
});
});
}
@ -153,15 +155,15 @@ module.exports = class ArchiveUtil {
err = Errors.ExternalProcess(`${action} failed: ${d.trim()}`);
}
});
proc.once('exit', exitCode => {
return cb(exitCode ? Errors.ExternalProcess(`${action} failed with exit code: ${exitCode}`) : err);
});
});
}
compressTo(archType, archivePath, files, cb) {
const archiver = this.getArchiver(archType);
if(!archiver) {
return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
}
@ -189,13 +191,13 @@ module.exports = class ArchiveUtil {
if(!cb && _.isFunction(fileList)) {
cb = fileList;
fileList = [];
haveFileList = false;
haveFileList = false;
} else {
haveFileList = true;
}
const archiver = this.getArchiver(archType);
if(!archiver) {
return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
}
@ -211,7 +213,7 @@ module.exports = class ArchiveUtil {
const args = archiver[action].args.map( arg => {
return '{fileList}' === arg ? arg : stringFormat(arg, fmtObj);
});
const fileListPos = args.indexOf('{fileList}');
if(fileListPos > -1) {
// replace {fileList} with 0:n sep file list arguments
@ -230,9 +232,9 @@ module.exports = class ArchiveUtil {
listEntries(archivePath, archType, cb) {
const archiver = this.getArchiver(archType);
if(!archiver) {
return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
}
const fmtObj = {
@ -240,7 +242,7 @@ module.exports = class ArchiveUtil {
};
const args = archiver.list.args.map( arg => stringFormat(arg, fmtObj) );
let proc;
try {
proc = pty.spawn(archiver.list.cmd, args, this.getPtyOpts());
@ -251,7 +253,7 @@ module.exports = class ArchiveUtil {
let output = '';
proc.on('data', data => {
// :TODO: hack for: execvp(3) failed.: No such file or directory
output += data;
});
@ -273,16 +275,16 @@ module.exports = class ArchiveUtil {
}
return cb(null, entries);
});
});
}
getPtyOpts() {
return {
// :TODO: cwd
name : 'enigma-archiver',
cols : 80,
rows : 24,
env : process.env,
env : process.env,
};
}
};

View File

@ -33,7 +33,7 @@ const SUPPORTED_ART_TYPES = {
'.pcb' : { name : 'PCBoard', defaultEncoding : 'cp437', eof : 0x1a },
'.bbs' : { name : 'Wildcat', defaultEncoding : 'cp437', eof : 0x1a },
'.amiga' : { name : 'Amiga', defaultEncoding : 'amiga', eof : 0x1a },
'.amiga' : { name : 'Amiga', defaultEncoding : 'amiga', eof : 0x1a },
'.txt' : { name : 'Amiga Text', defaultEncoding : 'cp437', eof : 0x1a },
// :TODO: extentions for wwiv, renegade, celerity, syncronet, ...
// :TODO: extension for atari
@ -93,7 +93,7 @@ function getArtFromPath(path, options, cb) {
}
return result;
}
}
if(options.readSauce === true) {
sauce.readSAUCE(data, (err, sauce) => {
@ -164,7 +164,7 @@ function getArt(name, options, cb) {
const bn = paths.basename(file, fext).toLowerCase();
if(options.random) {
const suppliedBn = paths.basename(name, fext).toLowerCase();
//
// Random selection enabled. We'll allow for
// basename1.ext, basename2.ext, ...
@ -208,7 +208,7 @@ function getArt(name, options, cb) {
return getArtFromPath(readPath, options, cb);
}
return cb(new Error(`No matching art for supplied criteria: ${name}`));
});
}
@ -287,7 +287,7 @@ function display(client, art, options, cb) {
return cb(null, mciMap, extraInfo);
}
if(!options.disableMciCache) {
if(!options.disableMciCache) {
artHash = xxhash.hash(new Buffer(art), 0xCAFEBABE);
// see if we have a mciMap cached for this art
@ -307,7 +307,7 @@ function display(client, art, options, cb) {
if(mciCprQueue.length > 0) {
mciMap[mciCprQueue.shift()].position = pos;
if(parseComplete && 0 === mciCprQueue.length) {
if(parseComplete && 0 === mciCprQueue.length) {
return completed();
}
}
@ -345,7 +345,7 @@ function display(client, art, options, cb) {
});
}
ansiParser.on('literal', literal => client.term.write(literal, false) );
ansiParser.on('literal', literal => client.term.write(literal, false) );
ansiParser.on('control', control => client.term.rawWrite(control) );
ansiParser.on('complete', () => {
@ -353,7 +353,7 @@ function display(client, art, options, cb) {
if(0 === mciCprQueue.length) {
return completed();
}
}
});
let initSeq = '';

View File

@ -31,7 +31,7 @@ const ALL_ASSETS = [
const ASSET_RE = new RegExp('\\@(' + ALL_ASSETS.join('|') + ')\\:([\\w\\d\\.]*)(?:\\/([\\w\\d\\_]+))*');
function parseAsset(s) {
function parseAsset(s) {
const m = ASSET_RE.exec(s);
if(m) {
@ -68,7 +68,7 @@ function getAssetWithShorthand(spec, defaultType) {
function getArtAsset(spec) {
const asset = getAssetWithShorthand(spec, 'art');
if(!asset) {
return null;
}
@ -79,7 +79,7 @@ function getArtAsset(spec) {
function getModuleAsset(spec) {
const asset = getAssetWithShorthand(spec, 'systemModule');
if(!asset) {
return null;
}
@ -105,7 +105,7 @@ function resolveConfigAsset(spec) {
return conf;
} else {
return spec;
}
}
}
function resolveSystemStatAsset(spec) {

View File

@ -182,7 +182,7 @@ function initialize(cb) {
return database.initializeDatabases(callback);
},
function initMimeTypes(callback) {
return require('./mime_util.js').startup(callback);
return require('./mime_util.js').startup(callback);
},
function initStatLog(callback) {
return require('./stat_log.js').init(callback);

View File

@ -23,10 +23,10 @@ const packageJson = require('../package.json');
authCode: XXXXX
schemeCode: XXXX
door: lord
// default hoss: games.bbslink.net
host: games.bbslink.net
// defualt port: 23
port: 23
}
@ -49,7 +49,7 @@ exports.getModule = class BBSLinkModule extends MenuModule {
this.config = options.menuConfig.config;
this.config.host = this.config.host || 'games.bbslink.net';
this.config.port = this.config.port || 23;
}
}
initSequence() {
let token;
@ -141,7 +141,7 @@ exports.getModule = class BBSLinkModule extends MenuModule {
self.client.once('end', function clientEnd() {
self.client.log.info('Connection ended. Terminating BBSLink connection');
clientTerminated = true;
bridgeConnection.end();
bridgeConnection.end();
});
});
@ -170,7 +170,7 @@ exports.getModule = class BBSLinkModule extends MenuModule {
],
function complete(err) {
if(err) {
self.client.log.warn( { error : err.toString() }, 'BBSLink connection error');
self.client.log.warn( { error : err.toString() }, 'BBSLink connection error');
}
if(!clientTerminated) {

View File

@ -4,7 +4,7 @@
// ENiGMA½
const MenuModule = require('./menu_module.js').MenuModule;
const {
const {
getModDatabasePath,
getTransactionDatabase
} = require('./database.js');
@ -39,7 +39,7 @@ const MciViewIds = {
SelectedBBSLoc : 6,
SelectedBBSSoftware : 7,
SelectedBBSNotes : 8,
SelectedBBSSubmitter : 9,
SelectedBBSSubmitter : 9,
},
add : {
BBSName : 1,
@ -49,7 +49,7 @@ const MciViewIds = {
Location : 5,
Software : 6,
Notes : 7,
Error : 8,
Error : 8,
}
};
@ -190,12 +190,12 @@ exports.getModule = class BBSListModule extends MenuModule {
drawSelectedEntry(entry) {
if(!entry) {
Object.keys(SELECTED_MCI_NAME_TO_ENTRY).forEach(mciName => {
Object.keys(SELECTED_MCI_NAME_TO_ENTRY).forEach(mciName => {
this.setViewText('view', MciViewIds.view[mciName], '');
});
} else {
const youSubmittedFormat = this.menuConfig.youSubmittedFormat || '{submitter} (You!)';
Object.keys(SELECTED_MCI_NAME_TO_ENTRY).forEach(mciName => {
const t = entry[SELECTED_MCI_NAME_TO_ENTRY[mciName]];
if(MciViewIds.view[mciName]) {
@ -270,7 +270,7 @@ exports.getModule = class BBSListModule extends MenuModule {
(err, row) => {
if (!err) {
self.entries.push({
id : row.id,
id : row.id,
bbsName : row.bbs_name,
sysOp : row.sysop,
telnet : row.telnet,
@ -306,9 +306,9 @@ exports.getModule = class BBSListModule extends MenuModule {
entriesView.on('index update', idx => {
const entry = self.entries[idx];
self.drawSelectedEntry(entry);
if(!entry) {
self.selectedBBS = -1;
} else {

View File

@ -22,7 +22,7 @@ ButtonView.prototype.onKeyPress = function(ch, key) {
if(this.isKeyMapped('accept', key.name) || ' ' === ch) {
this.submitData = 'accept';
this.emit('action', 'accept');
delete this.submitData;
delete this.submitData;
} else {
ButtonView.super_.prototype.onKeyPress.call(this, ch, key);
}

View File

@ -52,8 +52,8 @@ exports.Client = Client;
// Resources & Standards:
// * http://www.ansi-bbs.org/ansi-bbs-core-server.html
//
const RE_DSR_RESPONSE_ANYWHERE = /(?:\u001b\[)([0-9\;]+)(R)/;
const RE_DEV_ATTR_RESPONSE_ANYWHERE = /(?:\u001b\[)[\=\?]([0-9a-zA-Z\;]+)(c)/;
const RE_DSR_RESPONSE_ANYWHERE = /(?:\u001b\[)([0-9;]+)(R)/;
const RE_DEV_ATTR_RESPONSE_ANYWHERE = /(?:\u001b\[)[=?]([0-9a-zA-Z;]+)(c)/;
const RE_META_KEYCODE_ANYWHERE = /(?:\u001b)([a-zA-Z0-9])/;
const RE_META_KEYCODE = new RegExp('^' + RE_META_KEYCODE_ANYWHERE.source + '$');
const RE_FUNCTION_KEYCODE_ANYWHERE = new RegExp('(?:\u001b+)(O|N|\\[|\\[\\[)(?:' + [
@ -64,19 +64,19 @@ const RE_FUNCTION_KEYCODE_ANYWHERE = new RegExp('(?:\u001b+)(O|N|\\[|\\[\\[)(?:'
const RE_FUNCTION_KEYCODE = new RegExp('^' + RE_FUNCTION_KEYCODE_ANYWHERE.source);
const RE_ESC_CODE_ANYWHERE = new RegExp( [
RE_FUNCTION_KEYCODE_ANYWHERE.source,
RE_META_KEYCODE_ANYWHERE.source,
RE_FUNCTION_KEYCODE_ANYWHERE.source,
RE_META_KEYCODE_ANYWHERE.source,
RE_DSR_RESPONSE_ANYWHERE.source,
RE_DEV_ATTR_RESPONSE_ANYWHERE.source,
/\u001b./.source
].join('|'));
function Client(input, output) {
function Client(/*input, output*/) {
stream.call(this);
const self = this;
this.user = new User();
this.currentTheme = { info : { name : 'N/A', description : 'None' } };
this.lastKeyPressMs = Date.now();
@ -125,9 +125,9 @@ function Client(input, output) {
if(!termClient) {
if(_.startsWith(deviceAttr, '67;84;101;114;109')) {
//
//
// See https://github.com/protomouse/synchronet/blob/master/src/conio/cterm.txt
//
//
// Known clients:
// * SyncTERM
//
@ -139,11 +139,11 @@ function Client(input, output) {
};
this.isMouseInput = function(data) {
return /\x1b\[M/.test(data) ||
/\u001b\[M([\x00\u0020-\uffff]{3})/.test(data) ||
return /\x1b\[M/.test(data) || // eslint-disable-line no-control-regex
/\u001b\[M([\x00\u0020-\uffff]{3})/.test(data) || // eslint-disable-line no-control-regex
/\u001b\[(\d+;\d+;\d+)M/.test(data) ||
/\u001b\[<(\d+;\d+;\d+)([mM])/.test(data) ||
/\u001b\[<(\d+;\d+;\d+;\d+)&w/.test(data) ||
/\u001b\[<(\d+;\d+;\d+;\d+)&w/.test(data) ||
/\u001b\[24([0135])~\[(\d+),(\d+)\]\r/.test(data) ||
/\u001b\[(O|I)/.test(data);
};
@ -163,7 +163,7 @@ function Client(input, output) {
'OE' : { name : 'clear' },
'OF' : { name : 'end' },
'OH' : { name : 'home' },
// xterm/rxvt
'[11~' : { name : 'f1' },
'[12~' : { name : 'f2' },
@ -290,7 +290,7 @@ function Client(input, output) {
if(self.cprOffset) {
cprArgs[0] = cprArgs[0] + self.cprOffset;
cprArgs[1] = cprArgs[1] + self.cprOffset;
}
}
self.emit('cursor position report', cprArgs);
}
}
@ -299,7 +299,7 @@ function Client(input, output) {
var termClient = self.getTermClient(parts[1]);
if(termClient) {
self.term.termClient = termClient;
}
}
} else if('\r' === s) {
key.name = 'return';
} else if('\n' === s) {
@ -347,10 +347,10 @@ function Client(input, output) {
key.meta = true;
key.shift = /^[A-Z]$/.test(parts[1]);
} else if((parts = RE_FUNCTION_KEYCODE.exec(s))) {
var code =
var code =
(parts[1] || '') + (parts[2] || '') +
(parts[4] || '') + (parts[9] || '');
var modifier = (parts[3] || parts[8] || 1) - 1;
key.ctrl = !!(modifier & 4);
@ -375,7 +375,7 @@ function Client(input, output) {
//
// Adjust name for CTRL/Shift/Meta modifiers
//
key.name =
key.name =
(key.ctrl ? 'ctrl + ' : '') +
(key.meta ? 'meta + ' : '') +
(key.shift ? 'shift + ' : '') +
@ -446,7 +446,7 @@ Client.prototype.end = function () {
}
clearInterval(this.idleCheck);
try {
//
// We can end up calling 'end' before TTY/etc. is established, e.g. with SSH
@ -482,7 +482,7 @@ Client.prototype.isLocal = function() {
///////////////////////////////////////////////////////////////////////////////
// :TODO: getDefaultHandler(name) -- handlers in default_handlers.js or something
Client.prototype.defaultHandlerMissingMod = function(err) {
Client.prototype.defaultHandlerMissingMod = function() {
var self = this;
function handler(err) {
@ -493,12 +493,12 @@ Client.prototype.defaultHandlerMissingMod = function(err) {
self.term.write('This has been logged for your SysOp to review.\n');
self.term.write('\nGoodbye!\n');
//self.term.write(err);
//if(miscUtil.isDevelopment() && err.stack) {
// self.term.write('\n' + err.stack + '\n');
//}
//}
self.end();
}
@ -516,8 +516,8 @@ Client.prototype.terminalSupports = function(query) {
case 'vtx_hyperlink' :
return 'vtx' === termClient;
default :
default :
return false;
}
};

View File

@ -95,7 +95,7 @@ function removeClient(client) {
clientId : client.session.id
},
'Client disconnected'
);
);
Events.emit('codes.l33t.enigma.system.disconnected', { client : client, connectionCount : clientConnections.length } );
}

View File

@ -15,8 +15,6 @@ exports.ClientTerminal = ClientTerminal;
function ClientTerminal(output) {
this.output = output;
var self = this;
var outputEncoding = 'cp437';
assert(iconv.encodingExists(outputEncoding));
@ -56,7 +54,7 @@ function ClientTerminal(output) {
},
set : function(ttype) {
termType = ttype.toLowerCase();
if(this.isANSI()) {
this.outputEncoding = 'cp437';
} else {
@ -137,7 +135,7 @@ ClientTerminal.prototype.isANSI = function() {
//
// syncterm:
// * SyncTERM
//
//
// xterm:
// * PuTTY
//
@ -168,7 +166,7 @@ ClientTerminal.prototype.rawWrite = function(s, cb) {
if(cb) {
return cb(err);
}
if(err) {
Log.warn( { error : err.message }, 'Failed writing to socket');
}
@ -178,18 +176,18 @@ ClientTerminal.prototype.rawWrite = function(s, cb) {
ClientTerminal.prototype.pipeWrite = function(s, spec, cb) {
spec = spec || 'renegade';
var conv = {
enigma : enigmaToAnsi,
renegade : renegadeToAnsi,
}[spec] || renegadeToAnsi;
this.write(conv(s, this), null, cb); // null = use default for |convertLineFeeds|
};
ClientTerminal.prototype.encode = function(s, convertLineFeeds) {
convertLineFeeds = _.isBoolean(convertLineFeeds) ? convertLineFeeds : this.convertLF;
if(convertLineFeeds && _.isString(s)) {
s = s.replace(/\n/g, '\r\n');
}

View File

@ -68,14 +68,14 @@ function enigmaToAnsi(s, client) {
attr = ansi.sgr(['normal', val - 8, 'bold']);
}
result += s.substr(lastIndex, m.index - lastIndex) + attr;
result += s.substr(lastIndex, m.index - lastIndex) + attr;
}
lastIndex = re.lastIndex;
}
result = (0 === result.length ? s : result + s.substr(lastIndex));
return result;
}
@ -145,7 +145,7 @@ function renegadeToAnsi(s, client) {
}
// convert to number
val = parseInt(val, 10);
val = parseInt(val, 10);
if(isNaN(val)) {
val = getPredefinedMCIValue(client, m[1]) || ('|' + m[1]); // value itself or literal
}
@ -160,7 +160,7 @@ function renegadeToAnsi(s, client) {
lastIndex = re.lastIndex;
}
return (0 === result.length ? s : result + s.substr(lastIndex));
return (0 === result.length ? s : result + s.substr(lastIndex));
}
//
@ -180,7 +180,7 @@ function renegadeToAnsi(s, client) {
// * http://wiki.synchro.net/custom:colors
//
function controlCodesToAnsi(s, client) {
const RE = /(\|([A-Z0-9]{2})|\|)|(\@X([0-9A-F]{2}))|(\@([0-9A-F]{2})\@)|(\x03[0-9]|\x03)/g; // eslint-disable-line no-control-regex
const RE = /(\|([A-Z0-9]{2})|\|)|(@X([0-9A-F]{2}))|(@([0-9A-F]{2})@)|(\x03[0-9]|\x03)/g; // eslint-disable-line no-control-regex
let m;
let result = '';

View File

@ -25,10 +25,10 @@ exports.getModule = class CombatNetModule extends MenuModule {
this.config.host = this.config.host || 'bbs.combatnet.us';
this.config.rloginPort = this.config.rloginPort || 4513;
}
initSequence() {
const self = this;
async.series(
[
function validateConfig(callback) {
@ -45,59 +45,59 @@ exports.getModule = class CombatNetModule extends MenuModule {
self.client.term.write('Connecting to CombatNet, please wait...\n');
const restorePipeToNormal = function() {
self.client.term.output.removeListener('data', sendToRloginBuffer);
self.client.term.output.removeListener('data', sendToRloginBuffer);
};
const rlogin = new RLogin(
{ 'clientUsername' : self.config.password,
'serverUsername' : `${self.config.bbsTag}${self.client.user.username}`,
'host' : self.config.host,
'port' : self.config.rloginPort,
'terminalType' : self.client.term.termClient,
'terminalSpeed' : 57600
}
);
const rlogin = new RLogin(
{ 'clientUsername' : self.config.password,
'serverUsername' : `${self.config.bbsTag}${self.client.user.username}`,
'host' : self.config.host,
'port' : self.config.rloginPort,
'terminalType' : self.client.term.termClient,
'terminalSpeed' : 57600
}
);
// If there was an error ...
rlogin.on('error', err => {
self.client.log.info(`CombatNet rlogin client error: ${err.message}`);
restorePipeToNormal();
callback(err);
});
// If there was an error ...
rlogin.on('error', err => {
self.client.log.info(`CombatNet rlogin client error: ${err.message}`);
restorePipeToNormal();
return callback(err);
});
// If we've been disconnected ...
rlogin.on('disconnect', () => {
self.client.log.info(`Disconnected from CombatNet`);
restorePipeToNormal();
callback(null);
});
// If we've been disconnected ...
rlogin.on('disconnect', () => {
self.client.log.info('Disconnected from CombatNet');
restorePipeToNormal();
return callback(null);
});
function sendToRloginBuffer(buffer) {
rlogin.send(buffer);
};
function sendToRloginBuffer(buffer) {
rlogin.send(buffer);
}
rlogin.on("connect",
/* The 'connect' event handler will be supplied with one argument,
rlogin.on('connect',
/* The 'connect' event handler will be supplied with one argument,
a boolean indicating whether or not the connection was established. */
function(state) {
if(state) {
self.client.log.info('Connected to CombatNet');
self.client.term.output.on('data', sendToRloginBuffer);
function(state) {
if(state) {
self.client.log.info('Connected to CombatNet');
self.client.term.output.on('data', sendToRloginBuffer);
} else {
return callback(new Error('Failed to establish establish CombatNet connection'));
}
}
);
} else {
return callback(new Error('Failed to establish establish CombatNet connection'));
}
}
);
// If data (a Buffer) has been received from the server ...
rlogin.on("data", (data) => {
self.client.term.rawWrite(data);
});
// If data (a Buffer) has been received from the server ...
rlogin.on('data', (data) => {
self.client.term.rawWrite(data);
});
// connect...
rlogin.connect();
// connect...
rlogin.connect();
// note: no explicit callback() until we're finished!
}
@ -106,10 +106,10 @@ exports.getModule = class CombatNetModule extends MenuModule {
if(err) {
self.client.log.warn( { error : err.message }, 'CombatNet error');
}
// if the client is still here, go to previous
self.prevMenu();
}
);
}
}
};

View File

@ -10,7 +10,7 @@ exports.sortAreasOrConfs = sortAreasOrConfs;
// Method for sorting message, file, etc. areas and confs
// If the sort key is present and is a number, sort in numerical order;
// Otherwise, use a locale comparison on the sort key or name as a fallback
//
//
function sortAreasOrConfs(areasOrConfs, type) {
let entryA;
let entryB;

View File

@ -653,12 +653,12 @@ function getDefaultConfig() {
// FILE_ID.DIZ - https://en.wikipedia.org/wiki/FILE_ID.DIZ
// Some groups include a FILE_ID.ANS. We try to use that over FILE_ID.DIZ if available.
desc : [
'^[^/\]*FILE_ID\.ANS$', '^[^/\]*FILE_ID\.DIZ$', '^[^/\]*DESC\.SDI$', '^[^/\]*DESCRIPT\.ION$', '^[^/\]*FILE\.DES$', '^[^/\]*FILE\.SDI$', '^[^/\]*DISK\.ID$'
'^[^/\]*FILE_ID\.ANS$', '^[^/\]*FILE_ID\.DIZ$', '^[^/\]*DESC\.SDI$', '^[^/\]*DESCRIPT\.ION$', '^[^/\]*FILE\.DES$', '^[^/\]*FILE\.SDI$', '^[^/\]*DISK\.ID$' // eslint-disable-line no-useless-escape
],
// common README filename - https://en.wikipedia.org/wiki/README
descLong : [
'^[^/\]*\.NFO$', '^[^/\]*README\.1ST$', '^[^/\]*README\.NOW$', '^[^/\]*README\.TXT$', '^[^/\]*READ\.ME$', '^[^/\]*README$', '^[^/\]*README\.md$'
'^[^/\]*\.NFO$', '^[^/\]*README\.1ST$', '^[^/\]*README\.NOW$', '^[^/\]*README\.TXT$', '^[^/\]*READ\.ME$', '^[^/\]*README$', '^[^/\]*README\.md$' // eslint-disable-line no-useless-escape
],
},

View File

@ -58,7 +58,7 @@ util.inherits(ConfigCache, events.EventEmitter);
ConfigCache.prototype.getConfigWithOptions = function(options, cb) {
assert(_.isString(options.filePath));
// var self = this;
// var self = this;
var isCached = (options.filePath in this.cache);
if(options.forceReCache || !isCached) {

View File

@ -98,7 +98,7 @@ function ansiQueryTermSizeIfNeeded(client, cb) {
source : 'ANSI CPR'
},
'Window size updated'
);
);
return done(null);
};

View File

@ -10,7 +10,7 @@ exports.CRC32 = class CRC32 {
}
update(input) {
input = Buffer.isBuffer(input) ? input : Buffer.from(input, 'binary');
input = Buffer.isBuffer(input) ? input : Buffer.from(input, 'binary');
return input.length > 10240 ? this.update_8(input) : this.update_4(input);
}
@ -47,7 +47,7 @@ exports.CRC32 = class CRC32 {
this.crc = (this.crc >>> 8) ^ CRC32_TABLE[ (this.crc ^ input[i++] ) & 0xff ];
}
}
finalize() {
return (this.crc ^ (-1)) >>> 0;
}

View File

@ -36,12 +36,12 @@ function getModDatabasePath(moduleInfo, suffix) {
// Mods that use a database are stored in Config.paths.modsDb (e.g. enigma-bbs/db/mods)
// We expect that moduleInfo defines packageName which will be the base of the modules
// filename. An optional suffix may be supplied as well.
//
const HOST_RE = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
//
const HOST_RE = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/;
assert(_.isObject(moduleInfo));
assert(_.isString(moduleInfo.packageName), 'moduleInfo must define "packageName"!');
let full = moduleInfo.packageName;
if(suffix) {
full += `.${suffix}`;
@ -198,7 +198,7 @@ const DB_INIT_TABLE = {
DELETE FROM message_fts WHERE docid=old.rowid;
END;`
);
dbs.message.run(
`CREATE TRIGGER IF NOT EXISTS message_before_delete BEFORE DELETE ON message BEGIN
DELETE FROM message_fts WHERE docid=old.rowid;
@ -256,14 +256,14 @@ const DB_INIT_TABLE = {
UNIQUE(user_id, area_tag)
);`
);
dbs.message.run(
`CREATE TABLE IF NOT EXISTS message_area_last_scan (
scan_toss VARCHAR NOT NULL,
area_tag VARCHAR NOT NULL,
message_id INTEGER NOT NULL,
UNIQUE(scan_toss, area_tag)
);`
);`
);
return cb(null);

View File

@ -20,7 +20,7 @@ function Door(client, exeInfo) {
this.exeInfo = exeInfo;
this.exeInfo.encoding = this.exeInfo.encoding || 'cp437';
this.exeInfo.encoding = this.exeInfo.encoding.toLowerCase();
let restored = false;
let restored = false;
//
// Members of exeInfo:
@ -52,7 +52,7 @@ function Door(client, exeInfo) {
};
this.prepareSocketIoServer = function(cb) {
if('socket' === self.exeInfo.io) {
if('socket' === self.exeInfo.io) {
const sockServer = createServer(conn => {
sockServer.getConnections( (err, count) => {
@ -60,11 +60,11 @@ function Door(client, exeInfo) {
// We expect only one connection from our DOOR/emulator/etc.
if(!err && count <= 1) {
self.client.term.output.pipe(conn);
conn.on('data', self.doorDataHandler);
conn.once('end', () => {
return self.restoreIo(conn);
return self.restoreIo(conn);
});
conn.once('error', err => {
@ -117,7 +117,7 @@ Door.prototype.run = function() {
rows : self.client.term.termHeight,
// :TODO: cwd
env : self.exeInfo.env,
});
});
if('stdio' === self.exeInfo.io) {
self.client.log.debug('Using stdio for door I/O');

View File

@ -24,13 +24,13 @@ exports.getModule = class DoorPartyModule extends MenuModule {
this.config = options.menuConfig.config;
this.config.host = this.config.host || 'dp.throwbackbbs.com';
this.config.sshPort = this.config.sshPort || 2022;
this.config.rloginPort = this.config.rloginPort || 513;
this.config.rloginPort = this.config.rloginPort || 513;
}
initSequence() {
let clientTerminated;
const self = this;
async.series(
[
function validateConfig(callback) {
@ -48,26 +48,26 @@ exports.getModule = class DoorPartyModule extends MenuModule {
function establishSecureConnection(callback) {
self.client.term.write(resetScreen());
self.client.term.write('Connecting to DoorParty, please wait...\n');
const sshClient = new SSHClient();
let pipeRestored = false;
let pipedStream;
const restorePipe = function() {
if(pipedStream && !pipeRestored && !clientTerminated) {
self.client.term.output.unpipe(pipedStream);
self.client.term.output.unpipe(pipedStream);
self.client.term.output.resume();
}
};
}
};
sshClient.on('ready', () => {
// track client termination so we can clean up early
self.client.once('end', () => {
self.client.log.info('Connection ended. Terminating DoorParty connection');
clientTerminated = true;
sshClient.end();
sshClient.end();
});
// establish tunnel for rlogin
sshClient.forwardOut('127.0.0.1', self.config.sshPort, self.config.host, self.config.rloginPort, (err, stream) => {
if(err) {
@ -79,17 +79,17 @@ exports.getModule = class DoorPartyModule extends MenuModule {
// DoorParty wants the "server username" portion to be in the format of [BBS_TAG]USERNAME, e.g.
// [XA]nuskooler
//
const rlogin = `\x00${self.client.user.username}\x00[${self.config.bbsTag}]${self.client.user.username}\x00${self.client.term.termType}\x00`;
const rlogin = `\x00${self.client.user.username}\x00[${self.config.bbsTag}]${self.client.user.username}\x00${self.client.term.termType}\x00`;
stream.write(rlogin);
pipedStream = stream; // :TODO: this is hacky...
self.client.term.output.pipe(stream);
stream.on('data', d => {
// :TODO: we should just pipe this...
self.client.term.rawWrite(d);
});
stream.on('close', () => {
restorePipe();
sshClient.end();
@ -100,32 +100,32 @@ exports.getModule = class DoorPartyModule extends MenuModule {
sshClient.on('error', err => {
self.client.log.info(`DoorParty SSH client error: ${err.message}`);
});
sshClient.on('close', () => {
restorePipe();
callback(null);
});
sshClient.connect( {
host : self.config.host,
port : self.config.sshPort,
username : self.config.username,
password : self.config.password,
});
// note: no explicit callback() until we're finished!
}
}
],
err => {
if(err) {
self.client.log.warn( { error : err.message }, 'DoorParty error');
}
// if the client is stil here, go to previous
if(!clientTerminated) {
self.prevMenu();
}
}
);
}
}
};

View File

@ -59,14 +59,14 @@ module.exports = class DownloadQueue {
}
toProperty() { return JSON.stringify(this.client.user.downloadQueue); }
loadFromProperty(prop) {
try {
this.client.user.downloadQueue = JSON.parse(prop);
} catch(e) {
this.client.user.downloadQueue = [];
this.client.log.error( { error : e.message, property : prop }, 'Failed parsing download queue property');
this.client.log.error( { error : e.message, property : prop }, 'Failed parsing download queue property');
}
}
}
};

View File

@ -16,7 +16,7 @@ function EditTextView(options) {
options.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true);
options.cursorStyle = miscUtil.valueWithDefault(options.cursorStyle, 'steady block');
options.resizable = false;
TextView.call(this, options);
this.cursorPos = { row : 0, col : 0 };
@ -44,7 +44,7 @@ EditTextView.prototype.onKeyPress = function(ch, key) {
}
}
}
return EditTextView.super_.prototype.onKeyPress.call(this, ch, key);
} else if(this.isKeyMapped('clearLine', key.name)) {
this.text = '';

View File

@ -14,7 +14,7 @@ class EnigError extends Error {
if(typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor);
} else {
this.stack = (new Error(message)).stack;
this.stack = (new Error(message)).stack;
}
}
}

View File

@ -3,14 +3,14 @@
// ENiGMA½
const Config = require('./config.js').config;
const Log = require('./logger.js').log;
const Log = require('./logger.js').log;
// deps
const assert = require('assert');
module.exports = function(condition, message) {
if(Config.debug.assertsEnabled) {
assert.apply(this, arguments);
assert.apply(this, arguments);
} else if(!(condition)) {
const stack = new Error().stack;
Log.error( { condition : condition, stack : stack }, message || 'Assertion failed' );

View File

@ -37,12 +37,12 @@ var MciViewIds = {
function ErcClientModule(options) {
MenuModule.prototype.ctorShim.call(this, options);
const self = this;
const self = this;
this.config = options.menuConfig.config;
this.chatEntryFormat = this.config.chatEntryFormat || '[{bbsTag}] {userName}: {message}';
this.systemEntryFormat = this.config.systemEntryFormat || '[*SYSTEM*] {message}';
this.systemEntryFormat = this.config.systemEntryFormat || '[*SYSTEM*] {message}';
this.finishedLoading = function() {
async.waterfall(
[
@ -63,12 +63,12 @@ function ErcClientModule(options) {
};
const chatMessageView = self.viewControllers.menu.getView(MciViewIds.ChatDisplay);
chatMessageView.setText('Connecting to server...');
chatMessageView.redraw();
self.viewControllers.menu.switchFocus(MciViewIds.InputArea);
// :TODO: Track actual client->enig connection for optional prevMenu @ final CB
self.chatConnection = net.createConnection(connectOpts.port, connectOpts.host);
@ -98,12 +98,12 @@ function ErcClientModule(options) {
}
chatMessageView.addText(text);
if(chatMessageView.getLineCount() > 30) { // :TODO: should probably be ChatDisplay.height?
chatMessageView.deleteLine(0);
chatMessageView.scrollDown();
}
chatMessageView.redraw();
self.viewControllers.menu.switchFocus(MciViewIds.InputArea);
}

View File

@ -24,8 +24,8 @@ exports.moduleInfo = {
author : 'NuSkooler',
};
const SCHEDULE_REGEXP = /(?:^|or )?(@watch\:)([^\0]+)?$/;
const ACTION_REGEXP = /\@(method|execute)\:([^\0]+)?$/;
const SCHEDULE_REGEXP = /(?:^|or )?(@watch:)([^\0]+)?$/;
const ACTION_REGEXP = /@(method|execute):([^\0]+)?$/;
class ScheduledEvent {
constructor(events, name) {
@ -34,32 +34,32 @@ class ScheduledEvent {
this.action = this.parseActionSpec(events[name].action);
if(this.action) {
this.action.args = events[name].args || [];
}
}
}
get isValid() {
if((!this.schedule || (!this.schedule.sched && !this.schedule.watchFile)) || !this.action) {
return false;
}
if('method' === this.action.type && !this.action.location) {
return false;
}
return true;
return true;
}
parseScheduleString(schedStr) {
if(!schedStr) {
return false;
}
let schedule = {};
const m = SCHEDULE_REGEXP.exec(schedStr);
if(m) {
schedStr = schedStr.substr(0, m.index).trim();
if('@watch:' === m[1]) {
schedule.watchFile = m[2];
}
@ -69,15 +69,15 @@ class ScheduledEvent {
const sched = later.parse.text(schedStr);
if(-1 === sched.error) {
schedule.sched = sched;
}
}
}
// return undefined if we couldn't parse out anything useful
if(!_.isEmpty(schedule)) {
return schedule;
}
}
parseActionSpec(actionSpec) {
if(actionSpec) {
if('@' === actionSpec[0]) {
@ -86,7 +86,7 @@ class ScheduledEvent {
if(m[2].indexOf(':') > -1) {
const parts = m[2].split(':');
return {
type : m[1],
type : m[1],
location : parts[0],
what : parts[1],
};
@ -98,12 +98,12 @@ class ScheduledEvent {
}
}
} else {
return {
return {
type : 'execute',
what : actionSpec,
};
}
}
}
}
}
executeAction(reason, cb) {
@ -119,14 +119,14 @@ class ScheduledEvent {
{ error : err.toString(), eventName : this.name, action : this.action },
'Error performing scheduled event action');
}
return cb(err);
});
} catch(e) {
Log.warn(
{ error : e.toString(), eventName : this.name, action : this.action },
'Failed to perform scheduled event action');
return cb(e);
}
} else if('execute' === this.action.type) {
@ -135,18 +135,18 @@ class ScheduledEvent {
name : this.name,
cols : 80,
rows : 24,
env : process.env,
env : process.env,
};
const proc = pty.spawn(this.action.what, this.action.args, opts);
proc.once('exit', exitCode => {
proc.once('exit', exitCode => {
if(exitCode) {
Log.warn(
{ eventName : this.name, action : this.action, exitCode : exitCode },
'Bad exit code while performing scheduled event action');
}
return cb(exitCode ? new Error(`Bad exit code while performing scheduled event action: ${exitCode}`) : null);
return cb(exitCode ? new Error(`Bad exit code while performing scheduled event action: ${exitCode}`) : null);
});
}
}
@ -154,58 +154,58 @@ class ScheduledEvent {
function EventSchedulerModule(options) {
PluginModule.call(this, options);
if(_.has(Config, 'eventScheduler')) {
this.moduleConfig = Config.eventScheduler;
}
const self = this;
this.runningActions = new Set();
this.performAction = function(schedEvent, reason) {
if(self.runningActions.has(schedEvent.name)) {
return; // already running
}
}
self.runningActions.add(schedEvent.name);
schedEvent.executeAction(reason, () => {
self.runningActions.delete(schedEvent.name);
});
});
};
}
// convienence static method for direct load + start
EventSchedulerModule.loadAndStart = function(cb) {
const loadModuleEx = require('./module_util.js').loadModuleEx;
const loadOpts = {
name : path.basename(__filename, '.js'),
path : __dirname,
};
loadModuleEx(loadOpts, (err, mod) => {
if(err) {
return cb(err);
}
const modInst = new mod.getModule();
modInst.startup( err => {
return cb(err, modInst);
});
});
});
};
EventSchedulerModule.prototype.startup = function(cb) {
this.eventTimers = [];
const self = this;
if(this.moduleConfig && _.has(this.moduleConfig, 'events')) {
const events = Object.keys(this.moduleConfig.events).map( name => {
return new ScheduledEvent(this.moduleConfig.events, name);
});
events.forEach( schedEvent => {
if(!schedEvent.isValid) {
Log.warn( { eventName : schedEvent.name }, 'Invalid scheduled event entry');
@ -213,7 +213,7 @@ EventSchedulerModule.prototype.startup = function(cb) {
}
Log.debug(
{
{
eventName : schedEvent.name,
schedule : this.moduleConfig.events[schedEvent.name].schedule,
action : schedEvent.action,
@ -222,9 +222,9 @@ EventSchedulerModule.prototype.startup = function(cb) {
'Scheduled event loaded'
);
if(schedEvent.schedule.sched) {
if(schedEvent.schedule.sched) {
this.eventTimers.push(later.setInterval( () => {
self.performAction(schedEvent, 'Schedule');
self.performAction(schedEvent, 'Schedule');
}, schedEvent.schedule.sched));
}
@ -255,7 +255,7 @@ EventSchedulerModule.prototype.startup = function(cb) {
}
});
}
cb(null);
};
@ -263,6 +263,6 @@ EventSchedulerModule.prototype.shutdown = function(cb) {
if(this.eventTimers) {
this.eventTimers.forEach( et => et.clear() );
}
cb(null);
};

View File

@ -23,7 +23,7 @@ const SSHClient = require('ssh2').Client;
/*
Configuration block:
someDoor: {
module: exodus
config: {
@ -61,7 +61,7 @@ exports.getModule = class ExodusModule extends MenuModule {
this.config = options.menuConfig.config || {};
this.config.ticketHost = this.config.ticketHost || 'oddnetwork.org';
this.config.ticketPort = this.config.ticketPort || 1984,
this.config.ticketPath = this.config.ticketPath || '/exodus';
this.config.ticketPath = this.config.ticketPath || '/exodus';
this.config.rejectUnauthorized = _.get(this.config, 'rejectUnauthorized', true);
this.config.sshHost = this.config.sshHost || this.config.ticketHost;
this.config.sshPort = this.config.sshPort || 22;

View File

@ -65,7 +65,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule {
prevFilter : (formData, extraArgs, cb) => {
this.currentFilterIndex -= 1;
if(this.currentFilterIndex < 0) {
this.currentFilterIndex = this.filtersArray.length - 1;
this.currentFilterIndex = this.filtersArray.length - 1;
}
this.loadDataForFilter(this.currentFilterIndex);
return cb(null);
@ -116,21 +116,21 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule {
if(newActive) {
filters.setActive(newActive.uuid);
} else {
// nothing to set active to
// nothing to set active to
this.client.user.removeProperty('file_base_filter_active_uuid');
}
}
// update UI
this.updateActiveLabel();
if(this.filtersArray.length > 0) {
this.loadDataForFilter(this.currentFilterIndex);
} else {
this.clearForm();
}
return cb(null);
});
});
},
viewValidationListener : (err, cb) => {
@ -161,7 +161,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule {
}
}
}
mciReady(mciData, cb) {
super.mciReady(mciData, err => {
if(err) {
@ -178,7 +178,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule {
},
function populateAreas(callback) {
self.availAreas = [ { name : '-ALL-' } ].concat(getSortedAvailableFileAreas(self.client) || []);
const areasView = vc.getView(MciViewIds.editor.area);
if(areasView) {
areasView.setItems( self.availAreas.map( a => a.name ) );
@ -194,7 +194,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule {
return cb(err);
}
);
});
});
}
getCurrentFilter() {
@ -212,7 +212,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule {
const activeFilter = FileBaseFilters.getActiveFilter(this.client);
if(activeFilter) {
const activeFormat = this.menuConfig.config.activeFormat || '{name}';
this.setText(MciViewIds.editor.activeFilterInfo, stringFormat(activeFormat, activeFilter));
this.setText(MciViewIds.editor.activeFilterInfo, stringFormat(activeFormat, activeFilter));
}
}
@ -256,7 +256,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule {
setAreaIndexFromCurrentFilter() {
let index;
const filter = this.getCurrentFilter();
const filter = this.getCurrentFilter();
if(filter) {
// special treatment: areaTag saved as blank ("") if -ALL-
index = (filter.areaTag && this.availAreas.findIndex(area => filter.areaTag === area.areaTag)) || 0;
@ -295,7 +295,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule {
setFilterValuesFromFormData(filter, formData) {
filter.name = formData.value.name;
filter.areaTag = this.getSelectedAreaTag(formData.value.areaIndex);
filter.terms = formData.value.searchTerms;
filter.terms = formData.value.searchTerms;
filter.tags = formData.value.tags;
filter.order = this.getOrderBy(formData.value.orderByIndex);
filter.sort = this.getSortBy(formData.value.sortByIndex);
@ -304,7 +304,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule {
saveCurrentFilter(formData, cb) {
const filters = new FileBaseFilters(this.client);
const selectedFilter = this.filtersArray[this.currentFilterIndex];
if(selectedFilter) {
// *update* currently selected filter
this.setFilterValuesFromFormData(selectedFilter, formData);
@ -316,11 +316,11 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule {
// set current to what we just saved
newFilter.uuid = filters.add(newFilter);
// add to our array (at current index position)
this.filtersArray[this.currentFilterIndex] = newFilter;
}
return filters.persist(cb);
}
@ -334,6 +334,6 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule {
this.setAreaIndexFromCurrentFilter();
this.setSortByFromCurrentFilter();
this.setOrderByFromCurrentFilter();
}
}
}
};

View File

@ -96,7 +96,7 @@ exports.getModule = class FileAreaList extends MenuModule {
}
this.menuMethods = {
nextFile : (formData, extraArgs, cb) => {
nextFile : (formData, extraArgs, cb) => {
if(this.fileListPosition + 1 < this.fileList.length) {
this.fileListPosition += 1;
@ -131,7 +131,7 @@ exports.getModule = class FileAreaList extends MenuModule {
toggleQueue : (formData, extraArgs, cb) => {
this.dlQueue.toggle(this.currentFileEntry);
this.updateQueueIndicator();
return cb(null);
return cb(null);
},
showWebDownloadLink : (formData, extraArgs, cb) => {
return this.fetchAndDisplayWebDownloadLink(cb);
@ -217,7 +217,7 @@ exports.getModule = class FileAreaList extends MenuModule {
const hashTagsSep = config.hashTagsSep || ', ';
const isQueuedIndicator = config.isQueuedIndicator || 'Y';
const isNotQueuedIndicator = config.isNotQueuedIndicator || 'N';
const entryInfo = currEntry.entryInfo = {
fileId : currEntry.fileId,
areaTag : currEntry.areaTag,
@ -232,7 +232,7 @@ exports.getModule = class FileAreaList extends MenuModule {
hashTags : Array.from(currEntry.hashTags).join(hashTagsSep),
isQueued : this.dlQueue.isQueued(currEntry) ? isQueuedIndicator : isNotQueuedIndicator,
webDlLink : '', // :TODO: fetch web any existing web d/l link
webDlExpire : '', // :TODO: fetch web d/l link expire time
webDlExpire : '', // :TODO: fetch web d/l link expire time
};
//
@ -257,7 +257,7 @@ exports.getModule = class FileAreaList extends MenuModule {
// create a rating string, e.g. "**---"
const userRatingTicked = config.userRatingTicked || '*';
const userRatingUnticked = config.userRatingUnticked || '';
const userRatingUnticked = config.userRatingUnticked || '';
entryInfo.userRating = ~~Math.round(entryInfo.userRating) || 0; // be safe!
entryInfo.userRatingString = userRatingTicked.repeat(entryInfo.userRating);
if(entryInfo.userRating < 5) {
@ -270,7 +270,7 @@ exports.getModule = class FileAreaList extends MenuModule {
if(ErrNotEnabled === err.reasonCode) {
entryInfo.webDlExpire = config.webDlLinkNoWebserver || 'Web server is not enabled';
} else {
entryInfo.webDlLink = config.webDlLinkNeedsGenerated || 'Not yet generated';
entryInfo.webDlLink = config.webDlLinkNeedsGenerated || 'Not yet generated';
}
} else {
const webDlExpireTimeFormat = config.webDlExpireTimeFormat || 'YYYY-MMM-DD @ h:mm';
@ -339,10 +339,10 @@ exports.getModule = class FileAreaList extends MenuModule {
return vc.loadFromMenuConfig(loadOpts, callback);
}
self.viewControllers[name].setFocus(true);
return callback(null);
},
],
err => {
@ -357,7 +357,7 @@ exports.getModule = class FileAreaList extends MenuModule {
async.series(
[
function fetchEntryData(callback) {
if(self.fileList) {
if(self.fileList) {
return callback(null);
}
return self.loadFileIds(false, callback); // false=do not force
@ -371,14 +371,14 @@ exports.getModule = class FileAreaList extends MenuModule {
function prepArtAndViewController(callback) {
return self.displayArtAndPrepViewController('browse', { clearScreen : clearScreen }, callback);
},
function loadCurrentFileInfo(callback) {
function loadCurrentFileInfo(callback) {
self.currentFileEntry = new FileEntry();
self.currentFileEntry.load( self.fileList[ self.fileListPosition ], err => {
if(err) {
return callback(err);
}
return self.populateCurrentEntryInfo(callback);
});
},
@ -422,7 +422,7 @@ exports.getModule = class FileAreaList extends MenuModule {
return callback(null);
}
],
err => {
err => {
if(cb) {
return cb(err);
}
@ -448,7 +448,7 @@ exports.getModule = class FileAreaList extends MenuModule {
function listenNavChanges(callback) {
const navMenu = self.viewControllers.details.getView(MciViewIds.details.navMenu);
navMenu.setFocusItemIndex(0);
navMenu.on('index update', index => {
const sectionName = {
0 : 'general',
@ -481,7 +481,7 @@ exports.getModule = class FileAreaList extends MenuModule {
}
);
}
fetchAndDisplayWebDownloadLink(cb) {
const self = this;
@ -492,11 +492,11 @@ exports.getModule = class FileAreaList extends MenuModule {
if(self.currentFileEntry.webDlExpireTime < moment()) {
return callback(null);
}
const expireTime = moment().add(Config.fileBase.web.expireMinutes, 'minutes');
FileAreaWeb.createAndServeTempDownload(
self.client,
self.client,
self.currentFileEntry,
{ expireTime : expireTime },
(err, url) => {
@ -517,8 +517,8 @@ exports.getModule = class FileAreaList extends MenuModule {
},
function updateActiveViews(callback) {
self.updateCustomViewTextsWithFilter(
'browse',
MciViewIds.browse.customRangeStart, self.currentFileEntry.entryInfo,
'browse',
MciViewIds.browse.customRangeStart, self.currentFileEntry.entryInfo,
{ filter : [ '{webDlLink}', '{webDlExpire}' ] }
);
return callback(null);
@ -527,7 +527,7 @@ exports.getModule = class FileAreaList extends MenuModule {
err => {
return cb(err);
}
);
);
}
updateQueueIndicator() {
@ -535,8 +535,8 @@ exports.getModule = class FileAreaList extends MenuModule {
const isNotQueuedIndicator = this.menuConfig.config.isNotQueuedIndicator || 'N';
this.currentFileEntry.entryInfo.isQueued = stringFormat(
this.dlQueue.isQueued(this.currentFileEntry) ?
isQueuedIndicator :
this.dlQueue.isQueued(this.currentFileEntry) ?
isQueuedIndicator :
isNotQueuedIndicator
);
@ -558,7 +558,7 @@ exports.getModule = class FileAreaList extends MenuModule {
if(!areaInfo) {
return cb(Errors.Invalid('Invalid area tag'));
}
const filePath = this.currentFileEntry.filePath;
const archiveUtil = ArchiveUtil.getInstance();
@ -574,7 +574,7 @@ exports.getModule = class FileAreaList extends MenuModule {
populateFileListing() {
const fileListView = this.viewControllers.detailsFileList.getView(MciViewIds.detailsFileList.fileList);
if(this.currentFileEntry.entryInfo.archiveType) {
this.cacheArchiveEntries( (err, cacheStatus) => {
if(err) {
@ -586,7 +586,7 @@ exports.getModule = class FileAreaList extends MenuModule {
if('re-cached' === cacheStatus) {
const fileListEntryFormat = this.menuConfig.config.fileListEntryFormat || '{fileName} {fileSize}'; // :TODO: use byteSize here?
const focusFileListEntryFormat = this.menuConfig.config.focusFileListEntryFormat || fileListEntryFormat;
fileListView.setItems( this.currentFileEntry.archiveEntries.map( entry => stringFormat(fileListEntryFormat, entry) ) );
fileListView.setFocusItems( this.currentFileEntry.archiveEntries.map( entry => stringFormat(focusFileListEntryFormat, entry) ) );
@ -594,7 +594,7 @@ exports.getModule = class FileAreaList extends MenuModule {
}
});
} else {
fileListView.setItems( [ stringFormat(this.menuConfig.config.notAnArchiveFormat || 'Not an archive', { fileName : this.currentFileEntry.fileName } ) ] );
fileListView.setItems( [ stringFormat(this.menuConfig.config.notAnArchiveFormat || 'Not an archive', { fileName : this.currentFileEntry.fileName } ) ] );
}
}
@ -608,7 +608,7 @@ exports.getModule = class FileAreaList extends MenuModule {
if(self.lastDetailsViewController) {
self.lastDetailsViewController.detachClientEvents();
}
return callback(null);
return callback(null);
},
function prepArtAndViewController(callback) {
@ -616,7 +616,7 @@ exports.getModule = class FileAreaList extends MenuModule {
self.client.term.rawWrite(ansi.goto(self.detailsInfoArea.top[0], 1));
}
gotoTopPos();
gotoTopPos();
if(clearArea) {
self.client.term.rawWrite(ansi.reset());

View File

@ -59,7 +59,7 @@ class FileAreaWebAccess {
return callback(null); // not enabled, but no error
}
}
],
],
err => {
return cb(err);
}
@ -193,7 +193,7 @@ class FileAreaWebAccess {
getExistingTempDownloadServeItem(client, fileEntry, cb) {
if(!this.isEnabled()) {
return cb(notEnabledError());
}
}
const hashId = this.getSingleFileHashId(client, fileEntry);
this.loadServedHashId(hashId, (err, servedItem) => {
@ -201,10 +201,10 @@ class FileAreaWebAccess {
return cb(err);
}
servedItem.url = this.buildSingleFileTempDownloadLink(client, fileEntry);
servedItem.url = this.buildSingleFileTempDownloadLink(client, fileEntry);
return cb(null, servedItem);
});
});
}
_addOrUpdateHashIdRecord(dbOrTrans, hashId, expireTime, cb) {
@ -219,7 +219,7 @@ class FileAreaWebAccess {
}
this.scheduleExpire(hashId, expireTime);
return cb(null);
}
);
@ -476,7 +476,7 @@ class FileAreaWebAccess {
StatLog.incrementUserStat(user, 'dl_total_bytes', dlBytes);
StatLog.incrementSystemStat('dl_total_count', 1);
StatLog.incrementSystemStat('dl_total_bytes', dlBytes);
return callback(null);
}
],

View File

@ -61,8 +61,8 @@ function getAvailableFileAreas(client, options) {
// perform ACS check per conf & omit internal if desired
const allAreas = _.map(Config.fileBase.areas, (areaInfo, areaTag) => Object.assign(areaInfo, { areaTag : areaTag } ));
return _.omitBy(allAreas, areaInfo => {
return _.omitBy(allAreas, areaInfo => {
if(!options.includeSystemInternal && isInternalArea(areaInfo.areaTag)) {
return true;
}
@ -102,7 +102,7 @@ function getDefaultFileAreaTag(client, disableAcsCheck) {
defaultArea = _.findKey(Config.fileBase.areas, (area, areaTag) => {
return WellKnownAreaTags.MessageAreaAttach !== areaTag && (true === disableAcsCheck || client.acs.hasFileAreaRead(area));
});
return defaultArea;
}
@ -110,7 +110,7 @@ function getFileAreaByTag(areaTag) {
const areaInfo = Config.fileBase.areas[areaTag];
if(areaInfo) {
areaInfo.areaTag = areaTag; // convienence!
areaInfo.storage = getAreaStorageLocations(areaInfo);
areaInfo.storage = getAreaStorageLocations(areaInfo);
return areaInfo;
}
}
@ -165,13 +165,13 @@ function getAreaDefaultStorageDirectory(areaInfo) {
}
function getAreaStorageLocations(areaInfo) {
const storageTags = Array.isArray(areaInfo.storageTags) ?
areaInfo.storageTags :
const storageTags = Array.isArray(areaInfo.storageTags) ?
areaInfo.storageTags :
[ areaInfo.storageTags || '' ];
const avail = Config.fileBase.storageTags;
return _.compact(storageTags.map(storageTag => {
if(avail[storageTag]) {
return {
@ -230,7 +230,7 @@ function attemptSetEstimatedReleaseDate(fileEntry) {
const patterns = Config.fileBase.yearEstPatterns.map( p => new RegExp(p, 'gmi'));
function getMatch(input) {
if(input) {
if(input) {
let m;
for(let i = 0; i < patterns.length; ++i) {
m = patterns[i].exec(input);
@ -249,7 +249,7 @@ function attemptSetEstimatedReleaseDate(fileEntry) {
//
const maxYear = moment().add(2, 'year').year();
const match = getMatch(fileEntry.desc) || getMatch(fileEntry.descLong);
if(match && match[1]) {
let year;
if(2 === match[1].length) {
@ -316,7 +316,7 @@ function extractAndProcessDescFiles(fileEntry, filePath, archiveEntries, cb) {
archiveUtil.extractTo(filePath, tempDir, fileEntry.meta.archive_type, extractList, err => {
if(err) {
return callback(err);
}
}
const descFiles = {
desc : shortDescFile ? paths.join(tempDir, shortDescFile.fileName) : null,
@ -327,7 +327,7 @@ function extractAndProcessDescFiles(fileEntry, filePath, archiveEntries, cb) {
});
});
},
function readDescFiles(descFiles, callback) {
function readDescFiles(descFiles, callback) {
async.each(Object.keys(descFiles), (descType, next) => {
const path = descFiles[descType];
if(!path) {
@ -341,7 +341,7 @@ function extractAndProcessDescFiles(fileEntry, filePath, archiveEntries, cb) {
// skip entries that are too large
const maxFileSizeKey = `max${_.upperFirst(descType)}FileByteSize`;
if(Config.fileBase[maxFileSizeKey] && stats.size > Config.fileBase[maxFileSizeKey]) {
logDebug( { byteSize : stats.size, maxByteSize : Config.fileBase[maxFileSizeKey] }, `Skipping "${descType}"; Too large` );
return next(null);
@ -353,7 +353,7 @@ function extractAndProcessDescFiles(fileEntry, filePath, archiveEntries, cb) {
}
//
// Assume FILE_ID.DIZ, NFO files, etc. are CP437.
// Assume FILE_ID.DIZ, NFO files, etc. are CP437.
//
// :TODO: This isn't really always the case - how to handle this? We could do a quick detection...
fileEntry[descType] = iconv.decode(sliceAtSauceMarker(data, 0x1a), 'cp437');
@ -389,10 +389,10 @@ function extractAndProcessSingleArchiveEntry(fileEntry, filePath, archiveEntries
}
const archiveUtil = ArchiveUtil.getInstance();
// ensure we only extract one - there should only be one anyway -- we also just need the fileName
const extractList = archiveEntries.slice(0, 1).map(entry => entry.fileName);
archiveUtil.extractTo(filePath, tempDir, fileEntry.meta.archive_type, extractList, err => {
if(err) {
return callback(err);
@ -540,7 +540,7 @@ function populateFileEntryInfoFromFile(fileEntry, filePath, cb) {
});
}, () => {
return cb(null);
});
});
}
function populateFileEntryNonArchive(fileEntry, filePath, stepInfo, iterator, cb) {
@ -586,10 +586,6 @@ function addNewFileEntry(fileEntry, filePath, cb) {
);
}
function updateFileEntry(fileEntry, filePath, cb) {
}
const HASH_NAMES = [ 'sha1', 'sha256', 'md5', 'crc32' ];
function scanFile(filePath, options, iterator, cb) {
@ -664,7 +660,7 @@ function scanFile(filePath, options, iterator, cb) {
return callIter(callback);
});
},
function processPhysicalFileGeneric(callback) {
function processPhysicalFileGeneric(callback) {
stepInfo.bytesProcessed = 0;
const hashes = {};
@ -690,7 +686,7 @@ function scanFile(filePath, options, iterator, cb) {
stream.on('data', data => {
stream.pause(); // until iterator compeltes
stepInfo.bytesProcessed += data.length;
stepInfo.bytesProcessed += data.length;
stepInfo.calcHashPercent = Math.round(((stepInfo.bytesProcessed / stepInfo.byteSize) * 100));
//
@ -710,13 +706,13 @@ function scanFile(filePath, options, iterator, cb) {
updateHashes(data);
});
}
}
});
stream.on('end', () => {
fileEntry.meta.byte_size = stepInfo.bytesProcessed;
async.each(hashesToCalc, (hashName, nextHash) => {
async.each(hashesToCalc, (hashName, nextHash) => {
if('sha256' === hashName) {
stepInfo.sha256 = fileEntry.fileSha256 = hashes.sha256.digest('hex');
} else if('sha1' === hashName || 'md5' === hashName) {
@ -747,7 +743,9 @@ function scanFile(filePath, options, iterator, cb) {
populateFileEntryWithArchive(fileEntry, filePath, stepInfo, callIter, err => {
if(err) {
populateFileEntryNonArchive(fileEntry, filePath, stepInfo, callIter, err => {
// :TODO: log err
if(err) {
logDebug( { error : err.message }, 'Non-archive file entry population failed');
}
return callback(null); // ignore err
});
} else {
@ -756,7 +754,9 @@ function scanFile(filePath, options, iterator, cb) {
});
} else {
populateFileEntryNonArchive(fileEntry, filePath, stepInfo, callIter, err => {
// :TODO: log err
if(err) {
logDebug( { error : err.message }, 'Non-archive file entry population failed');
}
return callback(null); // ignore err
});
}
@ -773,7 +773,7 @@ function scanFile(filePath, options, iterator, cb) {
return callback(null, dupeEntries);
});
}
],
],
(err, dupeEntries) => {
if(err) {
return cb(err);
@ -858,12 +858,12 @@ function scanFileAreaForChanges(areaInfo, options, iterator, cb) {
// :TODO: Look @ db entries for area that were *not* processed above
return callback(null);
}
],
],
err => {
return nextLocation(err);
}
);
},
},
err => {
return cb(err);
});
@ -874,14 +874,14 @@ function getDescFromFileName(fileName) {
const ext = paths.extname(fileName);
const name = paths.basename(fileName, ext);
return _.upperFirst(name.replace(/[\-_.+]/g, ' ').replace(/\s+/g, ' '));
return _.upperFirst(name.replace(/[-_.+]/g, ' ').replace(/\s+/g, ' '));
}
//
// Return an object of stats about an area(s)
//
// {
//
//
// totalFiles : <totalFileCount>,
// totalBytes : <totalByteSize>,
// areas : {
@ -892,7 +892,7 @@ function getDescFromFileName(fileName) {
// }
// }
//
function getAreaStats(cb) {
function getAreaStats(cb) {
FileDb.all(
`SELECT DISTINCT f.area_tag, COUNT(f.file_id) AS total_files, SUM(m.meta_value) AS total_byte_size
FROM file f, file_meta m
@ -928,9 +928,9 @@ function getAreaStats(cb) {
// method exposed for event scheduler
function updateAreaStatsScheduledEvent(args, cb) {
getAreaStats( (err, stats) => {
getAreaStats( (err, stats) => {
if(!err) {
StatLog.setNonPeristentSystemStat('file_base_area_stats', stats);
StatLog.setNonPeristentSystemStat('file_base_area_stats', stats);
}
return cb(err);

View File

@ -38,7 +38,7 @@ exports.getModule = class FileAreaSelectModule extends MenuModule {
const menuOpts = {
extraArgs : {
filterCriteria : filterCriteria,
filterCriteria : filterCriteria,
},
menuFlags : [ 'popParent' ],
};

View File

@ -59,8 +59,6 @@ exports.getModule = class FileBaseDownloadQueueManager extends MenuModule {
return this.gotoMenu(this.menuConfig.config.fileTransferProtocolSelection || 'fileTransferProtocolSelection', modOpts, cb);
},
viewItemInfo : (formData, extraArgs, cb) => {
},
removeItem : (formData, extraArgs, cb) => {
const selectedItem = this.dlQueue.items[formData.value.queueItem];
if(!selectedItem) {
@ -74,7 +72,7 @@ exports.getModule = class FileBaseDownloadQueueManager extends MenuModule {
},
clearQueue : (formData, extraArgs, cb) => {
this.dlQueue.clear();
// :TODO: broken: does not redraw menu properly - needs fixed!
return this.removeItemsFromDownloadQueueView('all', cb);
}
@ -230,10 +228,10 @@ exports.getModule = class FileBaseDownloadQueueManager extends MenuModule {
return vc.loadFromMenuConfig(loadOpts, callback);
}
self.viewControllers[name].setFocus(true);
return callback(null);
},
],
err => {

View File

@ -8,7 +8,7 @@ const uuidV4 = require('uuid/v4');
module.exports = class FileBaseFilters {
constructor(client) {
this.client = client;
this.load();
}
@ -25,7 +25,7 @@ module.exports = class FileBaseFilters {
'est_release_year',
'byte_size',
'file_name',
];
];
}
toArray() {
@ -40,11 +40,11 @@ module.exports = class FileBaseFilters {
add(filterInfo) {
const filterUuid = uuidV4();
filterInfo.tags = this.cleanTags(filterInfo.tags);
this.filters[filterUuid] = filterInfo;
return filterUuid;
}
@ -94,18 +94,18 @@ module.exports = class FileBaseFilters {
}
cleanTags(tags) {
return tags.toLowerCase().replace(/,?\s+|\,/g, ' ').trim();
return tags.toLowerCase().replace(/,?\s+|,/g, ' ').trim();
}
setActive(filterUuid) {
const activeFilter = this.get(filterUuid);
if(activeFilter) {
this.activeFilter = activeFilter;
this.client.user.persistProperty('file_base_filter_active_uuid', filterUuid);
return true;
}
return false;
}

View File

@ -110,7 +110,7 @@ exports.getModule = class FileBaseSearch extends MenuModule {
const menuOpts = {
extraArgs : {
filterCriteria : filterCriteria,
filterCriteria : filterCriteria,
},
menuFlags : [ 'popParent' ],
};

View File

@ -32,13 +32,13 @@ const MciViewIds = {
queueManager : {
queue : 1,
navMenu : 2,
customRangeStart : 10,
}
};
exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
constructor(options) {
super(options);
@ -58,7 +58,7 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
},
clearQueue : (formData, extraArgs, cb) => {
this.dlQueue.clear();
// :TODO: broken: does not redraw menu properly - needs fixed!
return this.removeItemsFromDownloadQueueView('all', cb);
},
@ -109,7 +109,7 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
displayFileInfoForFileEntry(fileEntry) {
this.updateCustomViewTextsWithFilter(
'queueManager',
'queueManager',
MciViewIds.queueManager.customRangeStart, fileEntry,
{ filter : [ '{webDlLink}', '{webDlExpire}', '{fileName}' ] } // :TODO: Others....
);
@ -142,7 +142,7 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
const expireTime = moment().add(Config.fileBase.web.expireMinutes, 'minutes');
FileAreaWeb.createAndServeTempBatchDownload(
this.client,
this.client,
this.dlQueue.items,
{
expireTime : expireTime
@ -162,7 +162,7 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
this.updateCustomViewTextsWithFilter(
'queueManager',
MciViewIds.queueManager.customRangeStart,
MciViewIds.queueManager.customRangeStart,
formatObj,
{ filter : Object.keys(formatObj).map(k => '{' + k + '}' ) }
);
@ -187,13 +187,13 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
FileAreaWeb.getExistingTempDownloadServeItem(self.client, fileEntry, (err, serveItem) => {
if(err) {
if(ErrNotEnabled === err.reasonCode) {
return nextFileEntry(err); // we should have caught this prior
return nextFileEntry(err); // we should have caught this prior
}
const expireTime = moment().add(Config.fileBase.web.expireMinutes, 'minutes');
FileAreaWeb.createAndServeTempDownload(
self.client,
self.client,
fileEntry,
{ expireTime : expireTime },
(err, url) => {
@ -202,13 +202,13 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
}
fileEntry.webDlLinkRaw = url;
fileEntry.webDlLink = ansi.vtxHyperlink(self.client, url) + url;
fileEntry.webDlLink = ansi.vtxHyperlink(self.client, url) + url;
fileEntry.webDlExpire = expireTime.format(webDlExpireTimeFormat);
return nextFileEntry(null);
}
);
} else {
} else {
fileEntry.webDlLinkRaw = serveItem.url;
fileEntry.webDlLink = ansi.vtxHyperlink(self.client, serveItem.url) + serveItem.url;
fileEntry.webDlExpire = moment(serveItem.expireTimestamp).format(webDlExpireTimeFormat);
@ -272,10 +272,10 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
return vc.loadFromMenuConfig(loadOpts, callback);
}
self.viewControllers[name].setFocus(true);
return callback(null);
},
],
err => {
@ -284,4 +284,3 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
);
}
};

View File

@ -15,7 +15,7 @@ const { unlink, readFile } = require('graceful-fs');
const crypto = require('crypto');
const moment = require('moment');
const FILE_TABLE_MEMBERS = [
const FILE_TABLE_MEMBERS = [
'file_id', 'area_tag', 'file_sha256', 'file_name', 'storage_tag',
'desc', 'desc_long', 'upload_timestamp'
];
@ -47,7 +47,7 @@ module.exports = class FileEntry {
// values we always want
dl_count : 0,
};
this.hashTags = options.hashTags || new Set();
this.fileName = options.fileName;
this.storageTag = options.storageTag;
@ -173,7 +173,7 @@ module.exports = class FileEntry {
async.each(Object.keys(self.meta), (n, next) => {
const v = self.meta[n];
return FileEntry.persistMetaValue(self.fileId, n, v, trans, next);
},
},
err => {
return callback(err, trans);
});
@ -185,7 +185,7 @@ module.exports = class FileEntry {
},
err => {
return callback(err, trans);
});
});
}
],
(err, trans) => {
@ -203,10 +203,10 @@ module.exports = class FileEntry {
static getAreaStorageDirectoryByTag(storageTag) {
const storageLocation = (storageTag && Config.fileBase.storageTags[storageTag]);
// absolute paths as-is
if(storageLocation && '/' === storageLocation.charAt(0)) {
return storageLocation;
return storageLocation;
}
// relative to |areaStoragePrefix|
@ -283,7 +283,7 @@ module.exports = class FileEntry {
transOrDb.serialize( () => {
transOrDb.run(
`INSERT OR IGNORE INTO hash_tag (hash_tag)
VALUES (?);`,
VALUES (?);`,
[ hashTag ]
);
@ -321,7 +321,7 @@ module.exports = class FileEntry {
err => {
return cb(err);
}
);
);
}
loadRating(cb) {
@ -352,7 +352,7 @@ module.exports = class FileEntry {
}
static get WellKnownMetaValues() {
return Object.keys(FILE_WELL_KNOWN_META);
return Object.keys(FILE_WELL_KNOWN_META);
}
static findFileBySha(sha, cb) {
@ -469,7 +469,7 @@ module.exports = class FileEntry {
sqlOrderBy = `ORDER BY avg_rating ${sqlOrderDir}`;
} else {
sql =
sql =
`SELECT DISTINCT f.file_id, f.${filter.sort}
FROM file f`;
@ -531,7 +531,7 @@ module.exports = class FileEntry {
)`
);
}
if(filter.tags && filter.tags.length > 0) {
// build list of quoted tags; filter.tags comes in as a space and/or comma separated values
const tags = filter.tags.replace(/,/g, ' ').replace(/\s{2,}/g, ' ').split(' ').map( tag => `"${tag}"` ).join(',');
@ -617,7 +617,7 @@ module.exports = class FileEntry {
const srcPath = srcFileEntry.filePath;
const dstDir = FileEntry.getAreaStorageDirectoryByTag(destStorageTag);
if(!dstDir) {
return cb(Errors.Invalid('Invalid storage tag'));
}

View File

@ -65,7 +65,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
}
if(options.extraArgs.sendQueue) {
this.sendQueue = options.extraArgs.sendQueue;
this.sendQueue = options.extraArgs.sendQueue;
}
if(options.extraArgs.recvFileName) {
@ -107,7 +107,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
return { path : item };
} else {
return item;
}
}
});
this.sentFileIds = [];
@ -137,7 +137,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
this.sendQueue.forEach(f => {
f.sent = true;
sentFiles.push(f.path);
});
this.client.log.info( { sentFiles : sentFiles }, `Successfully sent ${sentFiles.length} file(s)` );
@ -160,7 +160,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
this.sendQueue.forEach(f => {
f.sent = true;
sentFiles.push(f.path);
});
this.client.log.info( { sentFiles : sentFiles }, `Successfully sent ${sentFiles.length} file(s)` );
@ -180,16 +180,16 @@ exports.getModule = class TransferFileModule extends MenuModule {
}
return next(err);
});
}, err => {
}, err => {
return cb(err);
});
}
}
}
*/
moveFileWithCollisionHandling(src, dst, cb) {
//
// Move |src| -> |dst| renaming to file(1).ext, file(2).ext, etc.
// Move |src| -> |dst| renaming to file(1).ext, file(2).ext, etc.
// in the case of collisions.
//
const dstPath = paths.dirname(dst);
@ -283,7 +283,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
});
}, () => {
return cb(null);
});
});
});
}
});
@ -309,7 +309,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
temptmp.open( { prefix : TEMP_SUFFIX, suffix : '.txt' }, (err, tempFileInfo) => {
if(err) {
return callback(err); // failed to create it
return callback(err); // failed to create it
}
fs.write(tempFileInfo.fd, filePaths.join(SYSTEM_EOL));
@ -334,7 +334,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
return callback(null, args);
}
],
],
(err, args) => {
return cb(err, args);
}
@ -364,7 +364,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
const externalProc = pty.spawn(cmd, args, {
cols : this.client.term.termWidth,
rows : this.client.term.termHeight,
cwd : this.recvDirectory,
cwd : this.recvDirectory,
});
this.client.setTemporaryDirectDataHandler(data => {
@ -376,7 +376,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
externalProc.write(data);
}
});
externalProc.on('data', data => {
// needed for things like sz/rz
if(external.escapeTelnet) {
@ -393,12 +393,12 @@ exports.getModule = class TransferFileModule extends MenuModule {
externalProc.once('exit', (exitCode) => {
this.client.log.debug( { cmd : cmd, args : args, exitCode : exitCode }, 'Process exited' );
this.restorePipeAfterExternalProc();
externalProc.removeAllListeners();
return cb(exitCode ? Errors.ExternalProcess(`Process exited with exit code ${exitCode}`, 'EBADEXIT') : null);
});
});
}
executeExternalProtocolHandlerForSend(filePaths, cb) {
@ -413,7 +413,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
this.executeExternalProtocolHandler(args, err => {
return cb(err);
});
});
});
}
@ -434,7 +434,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
return { sentFileIds : this.sentFileIds };
} else {
return { recvFilePaths : this.recvFilePaths };
}
}
}
updateSendStats(cb) {
@ -478,11 +478,11 @@ exports.getModule = class TransferFileModule extends MenuModule {
fileIds.forEach(fileId => {
FileEntry.incrementAndPersistMetaValue(fileId, 'dl_count', 1);
});
return cb(null);
});
}
updateRecvStats(cb) {
let uploadBytes = 0;
let uploadCount = 0;
@ -519,7 +519,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
function validateConfig(callback) {
if(self.isSending()) {
if(!Array.isArray(self.sendQueue)) {
self.sendQueue = [ self.sendQueue ];
self.sendQueue = [ self.sendQueue ];
}
}
@ -555,7 +555,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
});
}
},
function cleanupTempFiles(callback) {
function cleanupTempFiles(callback) {
temptmp.cleanup( paths => {
Log.debug( { paths : paths, sessionId : temptmp.sessionId }, 'Temporary files cleaned up' );
});

View File

@ -64,7 +64,7 @@ exports.getModule = class FileTransferProtocolSelectModule extends MenuModule {
return this.gotoMenu(this.config.downloadFilesMenu || 'sendFilesToUser', modOpts, cb);
} else {
return this.gotoMenu(this.config.uploadFilesMenu || 'recvFilesFromUser', modOpts, cb);
}
}
},
};
}
@ -118,7 +118,7 @@ exports.getModule = class FileTransferProtocolSelectModule extends MenuModule {
protListView.redraw();
return callback(null);
return callback(null);
}
],
err => {

View File

@ -66,11 +66,11 @@ function moveOrCopyFileWithCollisionHandling(src, dst, operation, cb) {
(err, finalPath) => {
return cb(err, finalPath);
}
);
);
}
//
// Move |src| -> |dst| renaming to file(1).ext, file(2).ext, etc.
// Move |src| -> |dst| renaming to file(1).ext, file(2).ext, etc.
// in the case of collisions.
//
function moveFileWithCollisionHandling(src, dst, cb) {

View File

@ -7,7 +7,7 @@ let _ = require('lodash');
module.exports = class FNV1a {
constructor(data) {
this.hash = 0x811c9dc5;
if(!_.isUndefined(data)) {
this.update(data);
}
@ -17,7 +17,7 @@ module.exports = class FNV1a {
if(_.isNumber(data)) {
data = data.toString();
}
if(_.isString(data)) {
data = new Buffer(data);
}
@ -28,8 +28,8 @@ module.exports = class FNV1a {
for(let b of data) {
this.hash = this.hash ^ b;
this.hash +=
(this.hash << 24) + (this.hash << 8) + (this.hash << 7) +
this.hash +=
(this.hash << 24) + (this.hash << 8) + (this.hash << 7) +
(this.hash << 4) + (this.hash << 1);
}
@ -46,5 +46,5 @@ module.exports = class FNV1a {
get value() {
return this.hash & 0xffffffff;
}
}
};

View File

@ -39,7 +39,7 @@ exports.moduleInfo = {
TL2 - To
TL3 - Subject
TL4 - Area name
TL5 - Date/Time (TODO: format)
TL6 - Message number
TL7 - Mesage total (in area)
@ -50,7 +50,7 @@ exports.moduleInfo = {
TL12 - User1
TL13 - User2
Footer - Viewing
HM1 - Menu (prev/next/etc.)
@ -61,14 +61,14 @@ exports.moduleInfo = {
TL12 - User1 (fmt message object)
TL13 - User2
*/
const MciCodeIds = {
ViewModeHeader : {
From : 1,
To : 2,
Subject : 3,
DateTime : 5,
MsgNum : 6,
MsgTotal : 7,
@ -78,9 +78,9 @@ const MciCodeIds = {
ReplyToMsgID : 11,
// :TODO: ConfName
},
ViewModeFooter : {
MsgNum : 6,
MsgTotal : 7,
@ -90,7 +90,7 @@ const MciCodeIds = {
From : 1,
To : 2,
Subject : 3,
ErrorMsg : 13,
},
};
@ -116,12 +116,12 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
// toUserId
//
this.editorType = config.editorType;
this.editorMode = config.editorMode;
this.editorMode = config.editorMode;
if(config.messageAreaTag) {
this.messageAreaTag = config.messageAreaTag;
}
this.messageIndex = config.messageIndex || 0;
this.messageTotal = config.messageTotal || 0;
this.toUserId = config.toUserId || 0;
@ -160,7 +160,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
if(errMsgView) {
if(err) {
errMsgView.setText(err.message);
if(MciCodeIds.ViewModeHeader.Subject === err.view.getId()) {
// :TODO: for "area" mode, should probably just bail if this is emtpy (e.g. cancel)
}
@ -179,26 +179,24 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
self.switchFooter(function next(err) {
if(err) {
// :TODO:... what now?
console.log(err)
} else {
switch(self.footerMode) {
case 'editor' :
if(!_.isUndefined(self.viewControllers.footerEditorMenu)) {
//self.viewControllers.footerEditorMenu.setFocus(false);
self.viewControllers.footerEditorMenu.detachClientEvents();
}
self.viewControllers.body.switchFocus(1);
self.observeEditorEvents();
break;
return cb(err);
}
case 'editorMenu' :
self.viewControllers.body.setFocus(false);
self.viewControllers.footerEditorMenu.switchFocus(1);
break;
switch(self.footerMode) {
case 'editor' :
if(!_.isUndefined(self.viewControllers.footerEditorMenu)) {
self.viewControllers.footerEditorMenu.detachClientEvents();
}
self.viewControllers.body.switchFocus(1);
self.observeEditorEvents();
break;
default : throw new Error('Unexpected mode');
}
case 'editorMenu' :
self.viewControllers.body.setFocus(false);
self.viewControllers.footerEditorMenu.switchFocus(1);
break;
default : throw new Error('Unexpected mode');
}
return cb(null);
@ -210,9 +208,9 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
return cb(null);
},
appendQuoteEntry: function(formData, extraArgs, cb) {
// :TODO: Dont' use magic # ID's here
// :TODO: Dont' use magic # ID's here
const quoteMsgView = self.viewControllers.quoteBuilder.getView(1);
if(self.newQuoteBlock) {
self.newQuoteBlock = false;
@ -220,7 +218,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
quoteMsgView.addText(self.getQuoteByHeader());
}
const quoteText = self.viewControllers.quoteBuilder.getView(3).getItem(formData.value.quote);
quoteMsgView.addText(quoteText);
@ -339,7 +337,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
//
// Ensure first characters indicate ANSI for detection down
// the line (other boards/etc.). We also set explicit_encoding
// to packetAnsiMsgEncoding (generally cp437) as various boards
// to packetAnsiMsgEncoding (generally cp437) as various boards
// really don't like ANSI messages in UTF-8 encoding (they should!)
//
msgOpts.meta = { System : { 'explicit_encoding' : Config.scannerTossers.ftn_bso.packetAnsiMsgEncoding || 'cp437' } };
@ -351,7 +349,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
return cb(null);
}
setMessage(message) {
this.message = message;
@ -495,7 +493,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
// :TODO: We'd like to delete up to N rows, but this does not work
// in NetRunner:
self.client.term.rawWrite(ansi.reset() + ansi.deleteLine(3));
self.client.term.rawWrite(ansi.reset() + ansi.eraseLine(2));
}
callback(null);
@ -534,7 +532,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
art[n],
self.client,
{ font : self.menuConfig.font },
function displayed(err, artData) {
function displayed(err) {
next(err);
}
);
@ -561,7 +559,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
function complete(err) {
cb(err);
}
);
);
}
switchFooter(cb) {
@ -645,14 +643,13 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
],
function complete(err) {
if(err) {
// :TODO: This needs properly handled!
console.log(err)
self.client.log.warn( { error : err.message }, 'FSE init error');
} else {
self.isReady = true;
self.finishedLoading();
}
}
);
);
}
createInitialViews(mciData, cb) {
@ -666,7 +663,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
menuLoadOpts.mciMap = mciData.header.mciMap;
self.addViewController(
'header',
'header',
new ViewController( { client : self.client, formId : menuLoadOpts.formId } )
).loadFromMenuConfig(menuLoadOpts, function headerReady(err) {
callback(err);
@ -713,7 +710,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
},
function setInitialData(callback) {
switch(self.editorMode) {
switch(self.editorMode) {
case 'view' :
if(self.message) {
self.initHeaderViewMode();
@ -726,7 +723,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
}
}
break;
case 'edit' :
{
const fromView = self.viewControllers.header.getView(1);
@ -747,9 +744,9 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
callback(null);
},
function setInitialFocus(callback) {
switch(self.editorMode) {
case 'edit' :
case 'edit' :
self.switchToHeader();
break;
@ -763,10 +760,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
}
],
function complete(err) {
if(err) {
console.error(err)
}
cb(err);
return cb(err);
}
);
}
@ -774,7 +768,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
mciReadyHandler(mciData, cb) {
this.createInitialViews(mciData, err => {
// :TODO: Can probably be replaced with @systemMethod:validateUserNameExists when the framework is in
// :TODO: Can probably be replaced with @systemMethod:validateUserNameExists when the framework is in
// place - if this is for existing usernames else validate spec
/*
@ -787,7 +781,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
view.clearText();
self.viewControllers.headers.switchFocus(2);
}
});
});
}
});*/
@ -813,7 +807,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
if(modeView) {
this.client.term.rawWrite(ansi.savePos());
modeView.setText('insert' === mode ? 'INS' : 'OVR');
this.client.term.rawWrite(ansi.restorePos());
this.client.term.rawWrite(ansi.restorePos());
}
}
}
@ -824,7 +818,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
initHeaderViewMode() {
assert(_.isObject(this.message));
this.setHeaderText(MciCodeIds.ViewModeHeader.From, this.message.fromUserName);
this.setHeaderText(MciCodeIds.ViewModeHeader.To, this.message.toUserName);
this.setHeaderText(MciCodeIds.ViewModeHeader.Subject, this.message.subject);
@ -881,7 +875,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
//
this.newQuoteBlock = true;
const self = this;
async.waterfall(
[
function clearAndDisplayArt(callback) {
@ -892,23 +886,23 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
self.client.term.rawWrite(
ansi.goto(self.header.height + 1, 1) +
ansi.deleteLine(24 - self.header.height));
theme.displayThemeArt( { name : self.menuConfig.config.art.quote, client : self.client }, function displayed(err, artData) {
callback(err, artData);
});
},
function createViewsIfNecessary(artData, callback) {
var formId = self.getFormId('quoteBuilder');
if(_.isUndefined(self.viewControllers.quoteBuilder)) {
var menuLoadOpts = {
callingMenu : self,
formId : formId,
mciMap : artData.mciMap,
mciMap : artData.mciMap,
};
self.addViewController(
'quoteBuilder',
'quoteBuilder',
new ViewController( { client : self.client, formId : formId } )
).loadFromMenuConfig(menuLoadOpts, function quoteViewsReady(err) {
callback(err);
@ -954,10 +948,10 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
],
function complete(err) {
if(err) {
console.log(err) // :TODO: needs real impl.
self.client.log.warn( { error : err.message }, 'Error displaying quote builder');
}
}
);
);
}
observeEditorEvents() {
@ -1004,22 +998,22 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
var body = this.viewControllers.body.getView(1);
body.redraw();
this.viewControllers.body.switchFocus(1);
// :TODO: create method (DRY)
this.updateTextEditMode(body.getTextEditMode());
this.updateEditModePosition(body.getEditPosition());
this.observeEditorEvents();
}
quoteBuilderFinalize() {
// :TODO: fix magic #'s
const quoteMsgView = this.viewControllers.quoteBuilder.getView(1);
const msgView = this.viewControllers.body.getView(1);
let quoteLines = quoteMsgView.getData().trim();
if(quoteLines.length > 0) {
if(this.replyIsAnsi) {
const bodyMessageView = this.viewControllers.body.getView(1);
@ -1027,7 +1021,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
}
msgView.addText(`${quoteLines}\n\n`);
}
quoteMsgView.setText('');
this.footerMode = 'editor';
@ -1040,14 +1034,14 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
getQuoteByHeader() {
let quoteFormat = this.menuConfig.config.quoteFormats;
if(Array.isArray(quoteFormat)) {
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 || this.client.currentTheme.helpers.getDateTimeFormat();
return stringFormat(quoteFormat, {
const dtFormat = this.menuConfig.config.quoteDateTimeFormat || this.client.currentTheme.helpers.getDateTimeFormat();
return stringFormat(quoteFormat, {
dateTime : moment(this.replyToMessage.modTimestamp).format(dtFormat),
userName : this.replyToMessage.fromUserName,
});

View File

@ -3,8 +3,8 @@
const _ = require('lodash');
const FTN_ADDRESS_REGEXP = /^([0-9]+:)?([0-9]+)(\/[0-9]+)?(\.[0-9]+)?(@[a-z0-9\-\.]+)?$/i;
const FTN_PATTERN_REGEXP = /^([0-9\*]+:)?([0-9\*]+)(\/[0-9\*]+)?(\.[0-9\*]+)?(@[a-z0-9\-\.\*]+)?$/i;
const FTN_ADDRESS_REGEXP = /^([0-9]+:)?([0-9]+)(\/[0-9]+)?(\.[0-9]+)?(@[a-z0-9\-.]+)?$/i;
const FTN_PATTERN_REGEXP = /^([0-9*]+:)?([0-9*]+)(\/[0-9*]+)?(\.[0-9*]+)?(@[a-z0-9\-.*]+)?$/i;
module.exports = class Address {
constructor(addr) {
@ -133,7 +133,7 @@ module.exports = class Address {
static fromString(addrStr) {
const m = FTN_ADDRESS_REGEXP.exec(addrStr);
if(m) {
// start with a 2D
let addr = {
@ -165,7 +165,7 @@ module.exports = class Address {
let addrStr = `${this.zone}:${this.net}`;
// allow for e.g. '4D' or 5
// allow for e.g. '4D' or 5
const dim = parseInt(dimensions.toString()[0]);
if(dim >= 3) {

View File

@ -56,7 +56,7 @@ class PacketHeader {
this.capWordValidate = ((this.capWord & 0xff) << 8) | ((this.capWord >> 8) & 0xff); // swap
this.prodCodeHi = 0xfe; // see above
this.prodRevHi = 0;
this.prodRevHi = 0;
}
get origAddress() {
@ -84,9 +84,9 @@ class PacketHeader {
// See FSC-48
// :TODO: disabled for now until we have separate packet writers for 2, 2+, 2+48, and 2.2
/*if(address.point) {
/*if(address.point) {
this.auxNet = address.origNet;
this.origNet = -1;
this.origNet = -1;
} else {
this.origNet = address.net;
this.auxNet = 0;
@ -158,16 +158,16 @@ exports.PacketHeader = PacketHeader;
//
// * Type 2 FTS-0001 @ http://ftsc.org/docs/fts-0001.016 (Obsolete)
// * Type 2.2 FSC-0045 @ http://ftsc.org/docs/fsc-0045.001
// * Type 2+ FSC-0039 and FSC-0048 @ http://ftsc.org/docs/fsc-0039.004
// * Type 2+ FSC-0039 and FSC-0048 @ http://ftsc.org/docs/fsc-0039.004
// and http://ftsc.org/docs/fsc-0048.002
//
//
// Additional resources:
// * Writeup on differences between type 2, 2.2, and 2+:
// http://walon.org/pub/fidonet/FTSC-nodelists-etc./pkt-types.txt
//
function Packet(options) {
var self = this;
this.options = options || {};
this.parsePacketHeader = function(packetBuffer, cb) {
@ -240,11 +240,11 @@ function Packet(options) {
//
// See heuristics described in FSC-0048, "Receiving Type-2+ bundles"
//
const capWordValidateSwapped =
const capWordValidateSwapped =
((packetHeader.capWordValidate & 0xff) << 8) |
((packetHeader.capWordValidate >> 8) & 0xff);
if(capWordValidateSwapped === packetHeader.capWord &&
if(capWordValidateSwapped === packetHeader.capWord &&
0 != packetHeader.capWord &&
packetHeader.capWord & 0x0001)
{
@ -260,7 +260,7 @@ function Packet(options) {
// :TODO: should fill bytes be 0?
}
}
packetHeader.created = moment({
year : packetHeader.year,
month : packetHeader.month - 1, // moment uses 0 indexed months
@ -269,36 +269,36 @@ function Packet(options) {
minute : packetHeader.minute,
second : packetHeader.second
});
let ph = new PacketHeader();
_.assign(ph, packetHeader);
cb(null, ph);
});
};
this.getPacketHeaderBuffer = function(packetHeader) {
let buffer = new Buffer(FTN_PACKET_HEADER_SIZE);
buffer.writeUInt16LE(packetHeader.origNode, 0);
buffer.writeUInt16LE(packetHeader.destNode, 2);
buffer.writeUInt16LE(packetHeader.year, 4);
buffer.writeUInt16LE(packetHeader.month, 6);
buffer.writeUInt16LE(packetHeader.month, 6);
buffer.writeUInt16LE(packetHeader.day, 8);
buffer.writeUInt16LE(packetHeader.hour, 10);
buffer.writeUInt16LE(packetHeader.minute, 12);
buffer.writeUInt16LE(packetHeader.second, 14);
buffer.writeUInt16LE(packetHeader.baud, 16);
buffer.writeUInt16LE(FTN_PACKET_HEADER_TYPE, 18);
buffer.writeUInt16LE(-1 === packetHeader.origNet ? 0xffff : packetHeader.origNet, 20);
buffer.writeUInt16LE(packetHeader.destNet, 22);
buffer.writeUInt8(packetHeader.prodCodeLo, 24);
buffer.writeUInt8(packetHeader.prodRevHi, 25);
const pass = ftn.stringToNullPaddedBuffer(packetHeader.password, 8);
pass.copy(buffer, 26);
buffer.writeUInt16LE(packetHeader.origZone, 34);
buffer.writeUInt16LE(packetHeader.destZone, 36);
buffer.writeUInt16LE(packetHeader.auxNet, 38);
@ -311,7 +311,7 @@ function Packet(options) {
buffer.writeUInt16LE(packetHeader.origPoint, 50);
buffer.writeUInt16LE(packetHeader.destPoint, 52);
buffer.writeUInt32LE(packetHeader.prodData, 54);
return buffer;
};
@ -321,22 +321,22 @@ function Packet(options) {
buffer.writeUInt16LE(packetHeader.origNode, 0);
buffer.writeUInt16LE(packetHeader.destNode, 2);
buffer.writeUInt16LE(packetHeader.year, 4);
buffer.writeUInt16LE(packetHeader.month, 6);
buffer.writeUInt16LE(packetHeader.month, 6);
buffer.writeUInt16LE(packetHeader.day, 8);
buffer.writeUInt16LE(packetHeader.hour, 10);
buffer.writeUInt16LE(packetHeader.minute, 12);
buffer.writeUInt16LE(packetHeader.second, 14);
buffer.writeUInt16LE(packetHeader.baud, 16);
buffer.writeUInt16LE(FTN_PACKET_HEADER_TYPE, 18);
buffer.writeUInt16LE(-1 === packetHeader.origNet ? 0xffff : packetHeader.origNet, 20);
buffer.writeUInt16LE(packetHeader.destNet, 22);
buffer.writeUInt8(packetHeader.prodCodeLo, 24);
buffer.writeUInt8(packetHeader.prodRevHi, 25);
const pass = ftn.stringToNullPaddedBuffer(packetHeader.password, 8);
pass.copy(buffer, 26);
buffer.writeUInt16LE(packetHeader.origZone, 34);
buffer.writeUInt16LE(packetHeader.destZone, 36);
buffer.writeUInt16LE(packetHeader.auxNet, 38);
@ -376,9 +376,9 @@ function Packet(options) {
// likely need to re-decode as the specified encoding
// * SAUCE is binary-ish data, so we need to inspect for it before any
// decoding occurs
//
//
let messageBodyData = {
message : [],
message : [],
kludgeLines : {}, // KLUDGE:[value1, value2, ...] map
seenBy : [],
};
@ -411,7 +411,7 @@ function Packet(options) {
messageBodyData.kludgeLines[key] = value;
}
}
let encoding = 'cp437';
async.series(
@ -426,12 +426,12 @@ function Packet(options) {
if(!err) {
// we read some SAUCE - don't re-process that portion into the body
messageBodyBuffer = messageBodyBuffer.slice(0, sauceHeaderPosition) + messageBodyBuffer.slice(sauceHeaderPosition + sauce.SAUCE_SIZE);
// messageBodyBuffer = messageBodyBuffer.slice(0, sauceHeaderPosition);
// messageBodyBuffer = messageBodyBuffer.slice(0, sauceHeaderPosition);
messageBodyData.sauce = theSauce;
} else {
console.log(err)
Log.warn( { error : err.message }, 'Found what looks like to be a SAUCE record, but failed to read');
}
callback(null); // failure to read SAUCE is OK
return callback(null); // failure to read SAUCE is OK
});
} else {
callback(null);
@ -482,7 +482,7 @@ function Packet(options) {
Log.debug( { encoding : encoding, error : e.toString() }, 'Error decoding. Falling back to ASCII');
decoded = iconv.decode(messageBodyBuffer, 'ascii');
}
const messageLines = strUtil.splitTextAtTerms(decoded.replace(/\xec/g, ''));
let endOfMessage = false;
@ -491,13 +491,13 @@ function Packet(options) {
messageBodyData.message.push('');
return;
}
if(line.startsWith('AREA:')) {
messageBodyData.area = line.substring(line.indexOf(':') + 1).trim();
} else if(line.startsWith('--- ')) {
// Tear Lines are tracked allowing for specialized display/etc.
messageBodyData.tearLine = line;
} else if(/^[ ]{1,2}\* Origin\: /.test(line)) { // To spec is " * Origin: ..."
} else if(/^[ ]{1,2}\* Origin: /.test(line)) { // To spec is " * Origin: ..."
messageBodyData.originLine = line;
endOfMessage = true; // Anything past origin is not part of the message body
} else if(line.startsWith('SEEN-BY:')) {
@ -523,7 +523,7 @@ function Packet(options) {
}
);
};
this.parsePacketMessages = function(packetBuffer, iterator, cb) {
binary.parse(packetBuffer)
.word16lu('messageType')
@ -540,22 +540,22 @@ function Packet(options) {
.scan('message', NULL_TERM_BUFFER)
.tap(function tapped(msgData) { // no arrow function; want classic this
if(!msgData.messageType) {
// end marker -- no more messages
// end marker -- no more messages
return cb(null);
}
if(FTN_PACKET_MESSAGE_TYPE != msgData.messageType) {
return cb(new Error('Unsupported message type: ' + msgData.messageType));
}
const read =
const read =
14 + // fixed header size
msgData.modDateTime.length + 1 +
msgData.toUserName.length + 1 +
msgData.fromUserName.length + 1 +
msgData.subject.length + 1 +
msgData.message.length + 1;
//
// Convert null terminated arrays to strings
//
@ -575,7 +575,7 @@ function Packet(options) {
subject : convMsgData.subject,
modTimestamp : ftn.getDateFromFtnDateTime(convMsgData.modDateTime),
});
msg.meta.FtnProperty = {};
msg.meta.FtnProperty.ftn_orig_node = msgData.ftn_orig_node;
msg.meta.FtnProperty.ftn_dest_node = msgData.ftn_dest_node;
@ -587,31 +587,31 @@ function Packet(options) {
self.processMessageBody(msgData.message, messageBodyData => {
msg.message = messageBodyData.message;
msg.meta.FtnKludge = messageBodyData.kludgeLines;
if(messageBodyData.tearLine) {
msg.meta.FtnProperty.ftn_tear_line = messageBodyData.tearLine;
if(self.options.keepTearAndOrigin) {
msg.message += `\r\n${messageBodyData.tearLine}\r\n`;
}
}
if(messageBodyData.seenBy.length > 0) {
msg.meta.FtnProperty.ftn_seen_by = messageBodyData.seenBy;
}
if(messageBodyData.area) {
msg.meta.FtnProperty.ftn_area = messageBodyData.area;
}
if(messageBodyData.originLine) {
msg.meta.FtnProperty.ftn_origin = messageBodyData.originLine;
if(self.options.keepTearAndOrigin) {
msg.message += `${messageBodyData.originLine}\r\n`;
}
}
//
// If we have a UTC offset kludge (e.g. TZUTC) then update
// modDateTime with it
@ -619,7 +619,7 @@ function Packet(options) {
if(_.isString(msg.meta.FtnKludge.TZUTC) && msg.meta.FtnKludge.TZUTC.length > 0) {
msg.modDateTime = msg.modTimestamp.utcOffset(msg.meta.FtnKludge.TZUTC);
}
const nextBuf = packetBuffer.slice(read);
if(nextBuf.length > 0) {
let next = function(e) {
@ -629,12 +629,12 @@ function Packet(options) {
self.parsePacketMessages(nextBuf, iterator, cb);
}
};
iterator('message', msg, next);
} else {
cb(null);
}
});
});
});
};
@ -702,7 +702,7 @@ function Packet(options) {
//
// message: unbound length, NULL term'd
//
//
// We need to build in various special lines - kludges, area,
// seen-by, etc.
//
@ -716,7 +716,7 @@ function Packet(options) {
if(message.meta.FtnProperty.ftn_area) {
msgBody += `AREA:${message.meta.FtnProperty.ftn_area}\r`; // note: no ^A (0x01)
}
// :TODO: DRY with similar function in this file!
Object.keys(message.meta.FtnKludge).forEach(k => {
switch(k) {
@ -731,7 +731,7 @@ function Packet(options) {
break;
default :
msgBody += getAppendMeta(`\x01${k}`, message.meta.FtnKludge[k]);
msgBody += getAppendMeta(`\x01${k}`, message.meta.FtnKludge[k]);
break;
}
});
@ -780,22 +780,22 @@ function Packet(options) {
//
msgBody += getAppendMeta('SEEN-BY', message.meta.FtnProperty.ftn_seen_by); // note: no ^A (0x01)
msgBody += getAppendMeta('\x01PATH', message.meta.FtnKludge['PATH']);
let msgBodyEncoded;
try {
msgBodyEncoded = iconv.encode(msgBody + '\0', options.encoding);
} catch(e) {
msgBodyEncoded = iconv.encode(msgBody + '\0', 'ascii');
}
return callback(
null,
Buffer.concat( [
basicHeader,
toUserNameBuf,
fromUserNameBuf,
null,
Buffer.concat( [
basicHeader,
toUserNameBuf,
fromUserNameBuf,
subjectBuf,
msgBodyEncoded
msgBodyEncoded
])
);
}
@ -808,7 +808,7 @@ function Packet(options) {
this.writeMessage = function(message, ws, options) {
let basicHeader = new Buffer(34);
basicHeader.writeUInt16LE(FTN_PACKET_MESSAGE_TYPE, 0);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_orig_node, 2);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_dest_node, 4);
@ -827,7 +827,7 @@ function Packet(options) {
let encBuf = iconv.encode(message.toUserName + '\0', 'CP437').slice(0, 36);
encBuf[encBuf.length - 1] = '\0'; // ensure it's null term'd
ws.write(encBuf);
encBuf = iconv.encode(message.fromUserName + '\0', 'CP437').slice(0, 36);
encBuf[encBuf.length - 1] = '\0'; // ensure it's null term'd
ws.write(encBuf);
@ -839,7 +839,7 @@ function Packet(options) {
//
// message: unbound length, NULL term'd
//
//
// We need to build in various special lines - kludges, area,
// seen-by, etc.
//
@ -866,7 +866,7 @@ function Packet(options) {
if(message.meta.FtnProperty.ftn_area) {
msgBody += `AREA:${message.meta.FtnProperty.ftn_area}\r`; // note: no ^A (0x01)
}
Object.keys(message.meta.FtnKludge).forEach(k => {
switch(k) {
case 'PATH' : break; // skip & save for last
@ -889,8 +889,8 @@ function Packet(options) {
if(message.meta.FtnProperty.ftn_tear_line) {
msgBody += `${message.meta.FtnProperty.ftn_tear_line}\r`;
}
//
//
// Origin line should be near the bottom of a message
//
if(message.meta.FtnProperty.ftn_origin) {
@ -918,11 +918,11 @@ function Packet(options) {
if(err) {
return callback(err);
}
let next = function(e) {
callback(e);
};
iterator('header', header, next);
});
},
@ -934,7 +934,7 @@ function Packet(options) {
}
],
cb // complete
);
);
};
}
@ -954,7 +954,7 @@ Packet.Attribute = {
InTransit : 0x0020,
Orphan : 0x0040,
KillSent : 0x0080,
Local : 0x0100, // Message is from *this* system
Local : 0x0100, // Message is from *this* system
Hold : 0x0200,
Reserved0 : 0x0400,
FileRequest : 0x0800,
@ -998,7 +998,7 @@ Packet.prototype.writeHeader = function(ws, packetHeader) {
Packet.prototype.writeMessageEntry = function(ws, msgEntry) {
ws.write(msgEntry);
return msgEntry.length;
return msgEntry.length;
};
Packet.prototype.writeTerminator = function(ws) {
@ -1014,11 +1014,11 @@ Packet.prototype.writeStream = function(ws, messages, options) {
if(!_.isBoolean(options.terminatePacket)) {
options.terminatePacket = true;
}
if(_.isObject(options.packetHeader)) {
this.writePacketHeader(options.packetHeader, ws);
}
options.encoding = options.encoding || 'utf8';
messages.forEach(msg => {
@ -1034,12 +1034,12 @@ Packet.prototype.write = function(path, packetHeader, messages, options) {
if(!_.isArray(messages)) {
messages = [ messages ];
}
options = options || { encoding : 'utf8' }; // utf-8 = 'CHRS UTF-8 4'
this.writeStream(
fs.createWriteStream(path), // :TODO: specify mode/etc.
messages,
{ packetHeader : packetHeader, terminatePacket : true }
);
Object.assign( { packetHeader : packetHeader, terminatePacket : true }, options)
);
};

View File

@ -45,7 +45,7 @@ exports.getQuotePrefix = getQuotePrefix;
// See list here: https://github.com/Mithgol/node-fidonet-jam
function stringToNullPaddedBuffer(s, bufLen) {
function stringToNullPaddedBuffer(s, bufLen) {
let buffer = new Buffer(bufLen).fill(0x00);
let enc = iconv.encode(s, 'CP437').slice(0, bufLen);
for(let i = 0; i < enc.length; ++i) {
@ -56,7 +56,7 @@ function stringToNullPaddedBuffer(s, bufLen) {
//
// Convert a FTN style DateTime string to a Date object
//
//
// :TODO: Name the next couple methods better - for FTN *packets*
function getDateFromFtnDateTime(dateTime) {
//
@ -103,7 +103,7 @@ function getMessageSerialNumber(messageId) {
//
// Return a FTS-0009.001 compliant MSGID value given a message
// See http://ftsc.org/docs/fts-0009.001
//
//
// "A MSGID line consists of the string "^AMSGID:" (where ^A is a
// control-A (hex 01) and the double-quotes are not part of the
// string), followed by a space, the address of the originating
@ -113,9 +113,9 @@ function getMessageSerialNumber(messageId) {
// ^AMSGID: origaddr serialno
//
// The originating address should be specified in a form that
// constitutes a valid return address for the originating network.
// constitutes a valid return address for the originating network.
// If the originating address is enclosed in double-quotes, the
// entire string between the beginning and ending double-quotes is
// entire string between the beginning and ending double-quotes is
// considered to be the orginating address. A double-quote character
// within a quoted address is represented by by two consecutive
// double-quote characters. The serial number may be any eight
@ -123,13 +123,13 @@ function getMessageSerialNumber(messageId) {
// messages from a given system may have the same serial number
// within a three years. The manner in which this serial number is
// generated is left to the implementor."
//
//
//
// Examples & Implementations
//
// Synchronet: <msgNum>.<conf+area>@<ftnAddr> <serial>
// 2606.agora-agn_tst@46:1/142 19609217
//
//
// Mystic: <ftnAddress> <serial>
// 46:3/102 46686263
//
@ -145,10 +145,10 @@ function getMessageSerialNumber(messageId) {
//
function getMessageIdentifier(message, address, isNetMail = false) {
const addrStr = new Address(address).toString('5D');
return isNetMail ?
return isNetMail ?
`${addrStr} ${getMessageSerialNumber(message.messageId)}` :
`${message.messageId}.${message.areaTag.toLowerCase()}@${addrStr} ${getMessageSerialNumber(message.messageId)}`
;
;
}
//
@ -166,7 +166,7 @@ function getProductIdentifier() {
}
//
// Return a FRL-1004 style time zone offset for a
// Return a FRL-1004 style time zone offset for a
// 'TZUTC' kludge line
//
// http://ftsc.org/docs/frl-1004.002
@ -178,10 +178,10 @@ function getUTCTimeZoneOffset() {
//
// Get a FSC-0032 style quote prefix
// http://ftsc.org/docs/fsc-0032.001
//
//
function getQuotePrefix(name) {
let initials;
const parts = name.split(' ');
if(parts.length > 1) {
// First & Last initials - (Bryan Ashby -> BA)
@ -199,7 +199,7 @@ function getQuotePrefix(name) {
// http://ftsc.org/docs/fts-0004.001
//
function getOrigin(address) {
const origin = _.has(Config, 'messageNetworks.originLine') ?
const origin = _.has(Config, 'messageNetworks.originLine') ?
Config.messageNetworks.originLine :
Config.general.boardName;
@ -220,16 +220,12 @@ function getVia(address) {
/*
FRL-1005.001 states teh following format:
^AVia: <FTN Address> @YYYYMMDD.HHMMSS[.Precise][.Time Zone]
^AVia: <FTN Address> @YYYYMMDD.HHMMSS[.Precise][.Time Zone]
<Program Name> <Version> [Serial Number]<CR>
*/
const addrStr = new Address(address).toString('5D');
const dateTime = moment().utc().format('YYYYMMDD.HHmmSS.SSSS.UTC');
const version = packageJson.version
.replace(/\-/g, '.')
.replace(/alpha/,'a')
.replace(/beta/,'b');
const version = getCleanEnigmaVersion();
return `${addrStr} @${dateTime} ENiGMA1/2 ${version}`;
}
@ -272,7 +268,7 @@ function parseAbbreviatedNetNodeList(netNodes) {
const re = /([0-9]+)\/([0-9]+)\s?|([0-9]+)\s?/g;
let net;
let m;
let results = [];
let results = [];
while(null !== (m = re.exec(netNodes))) {
if(m[1] && m[2]) {
net = parseInt(m[1]);
@ -288,7 +284,7 @@ function parseAbbreviatedNetNodeList(netNodes) {
//
// Return a FTS-0004.001 SEEN-BY entry(s) that include
// all pre-existing SEEN-BY entries with the addition
// of |additions|.
// of |additions|.
//
// See http://ftsc.org/docs/fts-0004.001
// and notes at http://ftsc.org/docs/fsc-0043.002.
@ -324,9 +320,9 @@ function getUpdatedSeenByEntries(existingEntries, additions) {
if(!_.isArray(existingEntries)) {
existingEntries = [ existingEntries ];
}
if(!_.isString(additions)) {
additions = parseAbbreviatedNetNodeList(getAbbreviatedNetNodeList(additions));
additions = parseAbbreviatedNetNodeList(getAbbreviatedNetNodeList(additions));
}
additions = additions.sort(Address.getComparator());
@ -361,13 +357,13 @@ const ENCODING_TO_FTS_5003_001_CHARS = {
// level 1 - generally should not be used
ascii : [ 'ASCII', 1 ],
'us-ascii' : [ 'ASCII', 1 ],
// level 2 - 8 bit, ASCII based
cp437 : [ 'CP437', 2 ],
cp850 : [ 'CP850', 2 ],
// level 3 - reserved
// level 4
utf8 : [ 'UTF-8', 4 ],
'utf-8' : [ 'UTF-8', 4 ],
@ -381,7 +377,7 @@ function getCharacterSetIdentifierByEncoding(encodingName) {
function getEncodingFromCharacterSetIdentifier(chrs) {
const ident = chrs.split(' ')[0].toUpperCase();
// :TODO: fill in the rest!!!
return {
// level 1
@ -399,7 +395,7 @@ function getEncodingFromCharacterSetIdentifier(chrs) {
'SWISS' : 'iso-646',
'UK' : 'iso-646',
'ISO-10' : 'iso-646-10',
// level 2
'CP437' : 'cp437',
'CP850' : 'cp850',
@ -414,15 +410,15 @@ function getEncodingFromCharacterSetIdentifier(chrs) {
'LATIN-2' : 'iso-8859-2',
'LATIN-5' : 'iso-8859-9',
'LATIN-9' : 'iso-8859-15',
// level 4
'UTF-8' : 'utf8',
// deprecated stuff
'IBMPC' : 'cp1250', // :TODO: validate
'IBMPC' : 'cp1250', // :TODO: validate
'+7_FIDO' : 'cp866',
'+7' : 'cp866',
'+7' : 'cp866',
'MAC' : 'macroman', // :TODO: validate
}[ident];
}

View File

@ -63,7 +63,7 @@ function HorizontalMenuView(options) {
}
var text = strUtil.stylizeString(
item.text,
item.text,
this.hasFocus && item.focused ? self.focusTextStyle : self.textStyle);
var drawWidth = text.length + self.getSpacer().length * 2; // * 2 = sides
@ -72,7 +72,7 @@ function HorizontalMenuView(options) {
ansi.goto(self.position.row, item.col) +
(index === self.focusedItemIndex ? self.getFocusSGR() : self.getSGR()) +
strUtil.pad(text, drawWidth, self.fillChar, 'center')
);
);
};
}

View File

@ -44,7 +44,7 @@ module.exports = class KeyEntryView extends View {
if(key && 'tab' === key.name && !this.eatTabKey) {
return this.emit('action', 'next', key);
}
this.emit('action', 'accept');
// NOTE: we don't call super here. KeyEntryView is a special snowflake.
}
@ -69,7 +69,7 @@ module.exports = class KeyEntryView extends View {
}
break;
}
super.setPropertyValue(propName, propValue);
}

View File

@ -20,7 +20,7 @@ const _ = require('lodash');
location
affiliation
ts
*/
exports.moduleInfo = {
@ -65,7 +65,7 @@ exports.getModule = class LastCallersModule extends MenuModule {
function fetchHistory(callback) {
callersView = vc.getView(MciCodeIds.CallerList);
// fetch up
// fetch up
StatLog.getSystemLogEntries('user_login_history', StatLog.Order.TimestampDesc, 200, (err, lh) => {
loginHistory = lh;
@ -82,12 +82,12 @@ exports.getModule = class LastCallersModule extends MenuModule {
loginHistory = noOpLoginHistory;
}
}
//
// Finally, we need to trim up the list to the needed size
//
loginHistory = loginHistory.slice(0, callersView.dimens.height);
return callback(err);
});
},
@ -99,10 +99,10 @@ exports.getModule = class LastCallersModule extends MenuModule {
const dateTimeFormat = self.menuConfig.config.dateTimeFormat || 'ddd MMM DD';
async.each(
loginHistory,
loginHistory,
(item, next) => {
item.userId = parseInt(item.log_value);
item.ts = moment(item.timestamp).format(dateTimeFormat);
item.ts = moment(item.timestamp).format(dateTimeFormat);
User.getUserName(item.userId, (err, userName) => {
if(err) {

View File

@ -12,7 +12,7 @@ module.exports = class Log {
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
@ -29,9 +29,9 @@ module.exports = class Log {
err : bunyan.stdSerializers.err, // handle 'err' fields with stack/etc.
};
// try to remove sensitive info by default, e.g. 'password' fields
// try to remove sensitive info by default, e.g. 'password' fields
[ 'formData', 'formValue' ].forEach(keyName => {
serializers[keyName] = (fd) => Log.hideSensitive(fd);
serializers[keyName] = (fd) => Log.hideSensitive(fd);
});
this.log = bunyan.createLogger({
@ -46,7 +46,7 @@ module.exports = class Log {
if(!fs.statSync(logPath).isDirectory()) {
return new Error(`${logPath} is not a directory`);
}
return null;
} catch(e) {
if('ENOENT' === e.code) {

View File

@ -28,7 +28,7 @@ module.exports = class LoginServerModule extends ServerModule {
} else {
client.user.properties.theme_id = conf.config.preLoginTheme;
}
theme.setClientTheme(client, client.user.properties.theme_id);
return cb(null); // note: currently useless to use cb here - but this may change...again...
}
@ -37,7 +37,7 @@ module.exports = class LoginServerModule extends ServerModule {
//
// Start tracking the client. We'll assign it an ID which is
// just the index in our connections array.
//
//
if(_.isUndefined(client.session)) {
client.session = {};
}
@ -68,7 +68,7 @@ module.exports = class LoginServerModule extends ServerModule {
client.on('close', err => {
const logFunc = err ? logger.log.info : logger.log.debug;
logFunc( { clientId : client.session.id }, 'Connection closed');
clientConns.removeClient(client);
});
@ -80,7 +80,7 @@ module.exports = class LoginServerModule extends ServerModule {
// likely just doesn't exist
client.term.write('\nIdle timeout expired. Goodbye!\n');
client.end();
}
}
});
});
}

View File

@ -33,4 +33,4 @@ MailPacket.prototype.write = function(options) {
// emits 'packet' event per packet constructed
//
assert(_.isArray(options.messages));
}
};

View File

@ -6,7 +6,7 @@ const Message = require('./message.js');
exports.getAddressedToInfo = getAddressedToInfo;
const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
/*
Input Output

View File

@ -25,7 +25,7 @@ exports.MaskEditTextView = MaskEditTextView;
// :TODO:
// * Hint, e.g. YYYY/MM/DD
// * Return values with literals in place
//
//
function MaskEditTextView(options) {
options.acceptsFocus = miscUtil.valueWithDefault(options.acceptsFocus, true);
@ -49,7 +49,7 @@ function MaskEditTextView(options) {
this.drawText = function(s) {
var textToDraw = strUtil.stylizeString(s, this.hasFocus ? this.focusTextStyle : this.textStyle);
assert(textToDraw.length <= self.patternArray.length);
// draw out the text we have so far
@ -105,7 +105,7 @@ MaskEditTextView.maskPatternCharacterRegEx = {
MaskEditTextView.prototype.setText = function(text) {
MaskEditTextView.super_.prototype.setText.call(this, text);
if(this.patternArray) { // :TODO: This is a hack - see TextView ctor note about setText()
this.patternArrayPos = this.patternArray.length;
}
@ -130,14 +130,14 @@ MaskEditTextView.prototype.onKeyPress = function(ch, key) {
this.clientBackspace();
} else {
while(this.patternArrayPos > 0) {
if(_.isRegExp(this.patternArray[this.patternArrayPos])) {
if(_.isRegExp(this.patternArray[this.patternArrayPos])) {
this.text = this.text.substr(0, this.text.length - 1);
this.client.term.write(ansi.goto(this.position.row, this.getEndOfTextColumn() + 1));
this.clientBackspace();
break;
}
this.patternArrayPos--;
}
}
}
}
@ -162,7 +162,7 @@ MaskEditTextView.prototype.onKeyPress = function(ch, key) {
this.text += ch;
this.patternArrayPos++;
while(this.patternArrayPos < this.patternArray.length &&
while(this.patternArrayPos < this.patternArray.length &&
!_.isRegExp(this.patternArray[this.patternArrayPos]))
{
this.patternArrayPos++;
@ -186,11 +186,11 @@ MaskEditTextView.prototype.setPropertyValue = function(propName, value) {
MaskEditTextView.prototype.getData = function() {
var rawData = MaskEditTextView.super_.prototype.getData.call(this);
if(!rawData || 0 === rawData.length) {
return rawData;
}
var data = '';
assert(rawData.length <= this.patternArray.length);

View File

@ -4,13 +4,12 @@
// ENiGMA½
const TextView = require('./text_view.js').TextView;
const EditTextView = require('./edit_text_view.js').EditTextView;
const ButtonView = require('./button_view.js').ButtonView;
const ButtonView = require('./button_view.js').ButtonView;
const VerticalMenuView = require('./vertical_menu_view.js').VerticalMenuView;
const HorizontalMenuView = require('./horizontal_menu_view.js').HorizontalMenuView;
const SpinnerMenuView = require('./spinner_menu_view.js').SpinnerMenuView;
const ToggleMenuView = require('./toggle_menu_view.js').ToggleMenuView;
const HorizontalMenuView = require('./horizontal_menu_view.js').HorizontalMenuView;
const SpinnerMenuView = require('./spinner_menu_view.js').SpinnerMenuView;
const ToggleMenuView = require('./toggle_menu_view.js').ToggleMenuView;
const MaskEditTextView = require('./mask_edit_text_view.js').MaskEditTextView;
//const StatusBarView = require('./status_bar_view.js').StatusBarView;
const KeyEntryView = require('./key_entry_view.js');
const MultiLineEditTextView = require('./multi_line_edit_text_view.js').MultiLineEditTextView;
const getPredefinedMCIValue = require('./predefined_mci.js').getPredefinedMCIValue;
@ -37,7 +36,7 @@ MCIViewFactory.UserViewCodes = [
'XY',
];
MCIViewFactory.prototype.createFromMCI = function(mci, cb) {
MCIViewFactory.prototype.createFromMCI = function(mci) {
assert(mci.code);
assert(mci.id > 0);
assert(mci.position);
@ -78,7 +77,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci, cb) {
//
switch(mci.code) {
// Text Label (Text View)
case 'TL' :
case 'TL' :
setOption(0, 'textStyle');
setOption(1, 'justify');
setWidth(2);
@ -105,14 +104,14 @@ MCIViewFactory.prototype.createFromMCI = function(mci, cb) {
break;
// Multi Line Edit Text
case 'MT' :
case 'MT' :
// :TODO: apply params
view = new MultiLineEditTextView(options);
break;
// Pre-defined Label (Text View)
// :TODO: Currently no real point of PL -- @method replaces this pretty much... probably remove
case 'PL' :
case 'PL' :
if(mci.args.length > 0) {
options.text = getPredefinedMCIValue(this.client, mci.args[0]);
if(options.text) {
@ -126,7 +125,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci, cb) {
break;
// Button
case 'BT' :
case 'BT' :
if(mci.args.length > 0) {
options.dimens = { width : parseInt(mci.args[0], 10) };
}
@ -144,14 +143,14 @@ MCIViewFactory.prototype.createFromMCI = function(mci, cb) {
setOption(0, 'itemSpacing');
setOption(1, 'justify');
setOption(2, 'textStyle');
setFocusOption(0, 'focusTextStyle');
view = new VerticalMenuView(options);
break;
// Horizontal Menu
case 'HM' :
case 'HM' :
setOption(0, 'itemSpacing');
setOption(1, 'textStyle');
@ -165,7 +164,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci, cb) {
setOption(1, 'justify');
setFocusOption(0, 'focusTextStyle');
view = new SpinnerMenuView(options);
break;

View File

@ -17,17 +17,17 @@ const assert = require('assert');
const _ = require('lodash');
exports.MenuModule = class MenuModule extends PluginModule {
constructor(options) {
super(options);
super(options);
this.menuName = options.menuName;
this.menuConfig = options.menuConfig;
this.client = options.client;
this.menuConfig.options = options.menuConfig.options || {};
this.menuMethods = {}; // methods called from @method's
this.menuMethods = {}; // methods called from @method's
this.menuConfig.config = this.menuConfig.config || {};
this.cls = _.isBoolean(this.menuConfig.options.cls) ? this.menuConfig.options.cls : Config.menus.cls;
this.viewControllers = {};
@ -70,7 +70,7 @@ exports.MenuModule = class MenuModule extends PluginModule {
}
);
},
function moveToPromptLocation(callback) {
function moveToPromptLocation(callback) {
if(self.menuConfig.prompt) {
// :TODO: fetch and move cursor to prompt location, if supplied. See notes/etc. on placements
}
@ -171,10 +171,10 @@ exports.MenuModule = class MenuModule extends PluginModule {
}
nextMenu(cb) {
if(!this.haveNext()) {
if(!this.haveNext()) {
return this.prevMenu(cb); // no next, go to prev
}
return this.client.menuStack.next(cb);
}
@ -210,7 +210,7 @@ exports.MenuModule = class MenuModule extends PluginModule {
haveNext() {
return (_.isString(this.menuConfig.next) || _.isArray(this.menuConfig.next));
}
autoNextMenu(cb) {
const self = this;
@ -221,8 +221,8 @@ exports.MenuModule = class MenuModule extends PluginModule {
return self.prevMenu(cb);
}
}
if(_.has(this.menuConfig, 'runtime.autoNext') && true === this.menuConfig.runtime.autoNext) {
if(_.has(this.menuConfig, 'runtime.autoNext') && true === this.menuConfig.runtime.autoNext) {
if(this.hasNextTimeout()) {
setTimeout( () => {
return gotoNextMenu();
@ -297,10 +297,10 @@ exports.MenuModule = class MenuModule extends PluginModule {
if(options.clearScreen) {
this.client.term.rawWrite(ansi.resetScreen());
}
return theme.displayThemedAsset(
name,
this.client,
name,
this.client,
Object.assign( { font : this.menuConfig.config.font }, options ),
(err, artData) => {
if(cb) {
@ -361,7 +361,7 @@ exports.MenuModule = class MenuModule extends PluginModule {
pausePrompt(position, cb) {
if(!cb && _.isFunction(position)) {
cb = position;
position = null;
position = null;
}
this.optionalMoveToPosition(position);
@ -390,7 +390,7 @@ exports.MenuModule = class MenuModule extends PluginModule {
if(!view) {
return;
}
if(appendMultiLine && (view instanceof MultiLineEditTextView)) {
view.addText(text);
} else {
@ -401,7 +401,7 @@ exports.MenuModule = class MenuModule extends PluginModule {
updateCustomViewTextsWithFilter(formName, startId, fmtObj, options) {
options = options || {};
let textView;
let textView;
let customMciId = startId;
const config = this.menuConfig.config;
const endId = options.endId || 99; // we'll fail to get a view before 99

View File

@ -78,19 +78,19 @@ module.exports = class MenuStack {
// :TODO: leave() should really take a cb...
this.pop().instance.leave(); // leave & remove current
const previousModuleInfo = this.pop(); // get previous
if(previousModuleInfo) {
const opts = {
extraArgs : previousModuleInfo.extraArgs,
extraArgs : previousModuleInfo.extraArgs,
savedState : previousModuleInfo.savedState,
lastMenuResult : menuResult,
};
return this.goto(previousModuleInfo.name, opts, cb);
}
return cb(Errors.MenuStack('No previous menu available', 'NOPREV'));
}
@ -106,14 +106,14 @@ module.exports = class MenuStack {
if(currentModuleInfo && name === currentModuleInfo.name) {
if(cb) {
cb(Errors.MenuStack('Already at supplied menu', 'ALREADYTHERE'));
cb(Errors.MenuStack('Already at supplied menu', 'ALREADYTHERE'));
}
return;
}
const loadOpts = {
name : name,
client : self.client,
client : self.client,
};
if(_.isObject(options)) {

View File

@ -42,7 +42,7 @@ function getMenuConfig(client, name, cb) {
} else {
callback(null);
}
}
}
],
function complete(err) {
cb(err, menuConfig);
@ -53,7 +53,7 @@ function getMenuConfig(client, name, cb) {
function loadMenu(options, cb) {
assert(_.isObject(options));
assert(_.isString(options.name));
assert(_.isObject(options.client));
assert(_.isObject(options.client));
async.waterfall(
[
@ -88,7 +88,7 @@ function loadMenu(options, cb) {
return callback(err, modData);
});
},
},
function createModuleInstance(modData, callback) {
Log.trace(
{ moduleName : modData.name, extraArgs : options.extraArgs, config : modData.config, info : modData.mod.modInfo },
@ -98,11 +98,11 @@ function loadMenu(options, cb) {
try {
moduleInstance = new modData.mod.getModule({
menuName : options.name,
menuConfig : modData.config,
menuConfig : modData.config,
extraArgs : options.extraArgs,
client : options.client,
lastMenuResult : options.lastMenuResult,
});
});
} catch(e) {
return callback(e);
}
@ -143,7 +143,7 @@ function getFormConfigByIDAndMap(menuConfig, formId, mciMap, cb) {
Log.trace( { mciKey : mciReqKey }, 'Using exact configuration key match');
cb(null, formForId[mciReqKey]);
return;
}
}
//
// Generic match
@ -184,24 +184,24 @@ function handleAction(client, formData, conf, cb) {
switch(actionAsset.type) {
case 'method' :
case 'systemMethod' :
case 'systemMethod' :
if(_.isString(actionAsset.location)) {
return callModuleMenuMethod(
client,
actionAsset,
paths.join(Config.paths.mods, actionAsset.location),
formData,
conf.extraArgs,
client,
actionAsset,
paths.join(Config.paths.mods, actionAsset.location),
formData,
conf.extraArgs,
cb);
} else if('systemMethod' === actionAsset.type) {
// :TODO: Need to pass optional args here -- conf.extraArgs and args between e.g. ()
// :TODO: Probably better as system_method.js
return callModuleMenuMethod(
client,
actionAsset,
paths.join(__dirname, 'system_menu_method.js'),
formData,
conf.extraArgs,
client,
actionAsset,
paths.join(__dirname, 'system_menu_method.js'),
formData,
conf.extraArgs,
cb);
} else {
// local to current module
@ -209,7 +209,7 @@ function handleAction(client, formData, conf, cb) {
if(_.isFunction(currentModule.menuMethods[actionAsset.asset])) {
return currentModule.menuMethods[actionAsset.asset](formData, conf.extraArgs, cb);
}
const err = new Error('Method does not exist');
client.log.warn( { method : actionAsset.asset }, err.message);
return cb(err);
@ -222,14 +222,14 @@ function handleAction(client, formData, conf, cb) {
function handleNext(client, nextSpec, conf, cb) {
assert(_.isString(nextSpec) || _.isArray(nextSpec));
if(_.isArray(nextSpec)) {
nextSpec = client.acs.getConditionalValue(nextSpec, 'next');
}
const nextAsset = asset.getAssetWithShorthand(nextSpec, 'menu');
// :TODO: getAssetWithShorthand() can return undefined - handle it!
conf = conf || {};
const extraArgs = conf.extraArgs || {};
@ -252,7 +252,7 @@ function handleNext(client, nextSpec, conf, cb) {
const err = new Error('Method does not exist');
client.log.warn( { method : nextAsset.asset }, err.message);
return cb(err);
return cb(err);
}
case 'menu' :

View File

@ -16,7 +16,7 @@ exports.MenuView = MenuView;
function MenuView(options) {
options.acceptsFocus = miscUtil.valueWithDefault(options.acceptsFocus, true);
options.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true);
View.call(this, options);
this.disablePipe = options.disablePipe || false;
@ -65,11 +65,11 @@ util.inherits(MenuView, View);
MenuView.prototype.setItems = function(items) {
const self = this;
if(items) {
if(items) {
this.items = [];
items.forEach( itemText => {
this.items.push(
{
{
text : self.disablePipe ? itemText : pipeToAnsi(itemText, self.client)
}
);
@ -79,7 +79,7 @@ MenuView.prototype.setItems = function(items) {
MenuView.prototype.removeItem = function(index) {
this.items.splice(index, 1);
if(this.focusItems) {
this.focusItems.splice(index, 1);
}
@ -95,7 +95,7 @@ MenuView.prototype.getCount = function() {
return this.items.length;
};
MenuView.prototype.getItems = function() {
MenuView.prototype.getItems = function() {
return this.items.map( item => {
return item.text;
});
@ -140,7 +140,7 @@ MenuView.prototype.onKeyPress = function(ch, key) {
MenuView.prototype.setFocusItems = function(items) {
const self = this;
if(items) {
this.focusItems = [];
items.forEach( itemText => {
@ -183,7 +183,7 @@ MenuView.prototype.setHotKeys = function(hotKeys) {
this.hotKeys[key.toLowerCase()] = hotKeys[key];
}
} else {
this.hotKeys = hotKeys;
this.hotKeys = hotKeys;
}
}
};

View File

@ -9,9 +9,9 @@ const getISOTimestampString = require('./database.js').getISOTimestampString;
const Errors = require('./enig_error.js').Errors;
const ANSI = require('./ansi_term.js');
const {
const {
isAnsi, isFormattedLine,
splitTextAtTerms,
splitTextAtTerms,
renderSubstr
} = require('./string_util.js');
@ -45,7 +45,7 @@ function Message(options) {
this.fromUserName = options.fromUserName || '';
this.subject = options.subject || '';
this.message = options.message || '';
if(_.isDate(options.modTimestamp) || moment.isMoment(options.modTimestamp)) {
this.modTimestamp = moment(options.modTimestamp);
} else if(_.isString(options.modTimestamp)) {
@ -115,7 +115,7 @@ Message.StateFlags0 = {
Exported : 0x00000002, // exported to foreign system
};
Message.FtnPropertyNames = {
Message.FtnPropertyNames = {
FtnOrigNode : 'ftn_orig_node',
FtnDestNode : 'ftn_dest_node',
FtnOrigNetwork : 'ftn_orig_network',
@ -166,12 +166,12 @@ Message.createMessageUUID = function(areaTag, modTimestamp, subject, body) {
if(!moment.isMoment(modTimestamp)) {
modTimestamp = moment(modTimestamp);
}
areaTag = iconvEncode(areaTag.toUpperCase(), 'CP437');
modTimestamp = iconvEncode(modTimestamp.format('DD MMM YY HH:mm:ss'), 'CP437');
subject = iconvEncode(subject.toUpperCase().trim(), 'CP437');
body = iconvEncode(body.replace(/\r\n|[\n\v\f\r\x85\u2028\u2029]/g, '').trim(), 'CP437');
return uuidParse.unparse(createNamedUUID(ENIGMA_MESSAGE_UUID_NAMESPACE, Buffer.concat( [ areaTag, modTimestamp, subject, body ] )));
};
@ -180,8 +180,8 @@ Message.getMessageIdByUuid = function(uuid, cb) {
`SELECT message_id
FROM message
WHERE message_uuid = ?
LIMIT 1;`,
[ uuid ],
LIMIT 1;`,
[ uuid ],
(err, row) => {
if(err) {
cb(err);
@ -210,30 +210,30 @@ Message.getMessageIdsByMetaValue = function(category, name, value, cb) {
};
Message.getMetaValuesByMessageId = function(messageId, category, name, cb) {
const sql =
const sql =
`SELECT meta_value
FROM message_meta
WHERE message_id = ? AND meta_category = ? AND meta_name = ?;`;
msgDb.all(sql, [ messageId, category, name ], (err, rows) => {
if(err) {
return cb(err);
}
if(0 === rows.length) {
return cb(new Error('No value for category/name'));
}
// single values are returned without an array
if(1 === rows.length) {
return cb(null, rows[0].meta_value);
}
cb(null, rows.map(r => r.meta_value)); // map to array of values only
});
};
Message.getMetaValuesByMessageUuid = function(uuid, category, name, cb) {
Message.getMetaValuesByMessageUuid = function(uuid, category, name, cb) {
async.waterfall(
[
function getMessageId(callback) {
@ -256,22 +256,22 @@ Message.getMetaValuesByMessageUuid = function(uuid, category, name, cb) {
Message.prototype.loadMeta = function(cb) {
/*
Example of loaded this.meta:
meta: {
System: {
local_to_user_id: 1234,
local_to_user_id: 1234,
},
FtnProperty: {
ftn_seen_by: [ "1/102 103", "2/42 52 65" ]
}
}
*/
const sql =
}
*/
const sql =
`SELECT meta_category, meta_name, meta_value
FROM message_meta
WHERE message_id = ?;`;
let self = this;
msgDb.each(sql, [ this.messageId ], (err, row) => {
if(!(row.meta_category in self.meta)) {
@ -279,12 +279,12 @@ Message.prototype.loadMeta = function(cb) {
self.meta[row.meta_category][row.meta_name] = row.meta_value;
} else {
if(!(row.meta_name in self.meta[row.meta_category])) {
self.meta[row.meta_category][row.meta_name] = row.meta_value;
self.meta[row.meta_category][row.meta_name] = row.meta_value;
} else {
if(_.isString(self.meta[row.meta_category][row.meta_name])) {
self.meta[row.meta_category][row.meta_name] = [ self.meta[row.meta_category][row.meta_name] ];
self.meta[row.meta_category][row.meta_name] = [ self.meta[row.meta_category][row.meta_name] ];
}
self.meta[row.meta_category][row.meta_name].push(row.meta_value);
}
}
@ -315,7 +315,7 @@ Message.prototype.load = function(options, cb) {
if(!msgRow) {
return callback(new Error('Message (no longer) available'));
}
self.messageId = msgRow.message_id;
self.areaTag = msgRow.area_tag;
self.messageUuid = msgRow.message_uuid;
@ -356,13 +356,13 @@ Message.prototype.persistMetaValue = function(category, name, value, transOrDb,
const metaStmt = transOrDb.prepare(
`INSERT INTO message_meta (message_id, meta_category, meta_name, meta_value)
VALUES (?, ?, ?, ?);`);
if(!_.isArray(value)) {
value = [ value ];
}
let self = this;
async.each(value, (v, next) => {
metaStmt.run(self.messageId, category, name, v, err => {
next(err);
@ -379,7 +379,7 @@ Message.prototype.persist = function(cb) {
}
const self = this;
async.waterfall(
[
function beginTransaction(callback) {
@ -398,7 +398,7 @@ Message.prototype.persist = function(cb) {
trans.run(
`INSERT INTO message (area_tag, message_uuid, reply_to_message_id, to_user_name, from_user_name, subject, message, modified_timestamp)
VALUES (?, ?, ?, ?, ?, ?, ?, ?);`,
VALUES (?, ?, ?, ?, ?, ?, ?, ?);`,
[ self.areaTag, self.uuid, self.replyToMsgId, self.toUserName, self.fromUserName, self.subject, self.message, getISOTimestampString(msgTimestamp) ],
function inserted(err) { // use non-arrow function for 'this' scope
if(!err) {
@ -415,15 +415,15 @@ Message.prototype.persist = function(cb) {
}
/*
Example of self.meta:
meta: {
System: {
local_to_user_id: 1234,
local_to_user_id: 1234,
},
FtnProperty: {
ftn_seen_by: [ "1/102 103", "2/42 52 65" ]
}
}
}
*/
async.each(Object.keys(self.meta), (category, nextCat) => {
async.each(Object.keys(self.meta[category]), (name, nextName) => {
@ -433,10 +433,10 @@ Message.prototype.persist = function(cb) {
}, err => {
nextCat(err);
});
}, err => {
callback(err, trans);
});
});
},
function storeHashTags(trans, callback) {
// :TODO: hash tag support
@ -470,21 +470,21 @@ Message.prototype.getQuoteLines = function(options, cb) {
if(!options.termWidth || !options.termHeight || !options.cols) {
return cb(Errors.MissingParam());
}
options.startCol = options.startCol || 1;
options.includePrefix = _.get(options, 'includePrefix', true);
options.ansiResetSgr = options.ansiResetSgr || ANSI.getSGRFromGraphicRendition( { fg : 39, bg : 49 }, true);
options.ansiFocusPrefixSgr = options.ansiFocusPrefixSgr || ANSI.getSGRFromGraphicRendition( { intensity : 'bold', fg : 39, bg : 49 } );
options.isAnsi = options.isAnsi || isAnsi(this.message); // :TODO: If this.isAnsi, use that setting
/*
Some long text that needs to be wrapped and quoted should look right after
doing so, don't ya think? yeah I think so
doing so, don't ya think? yeah I think so
Nu> Some long text that needs to be wrapped and quoted should look right
Nu> Some long text that needs to be wrapped and quoted should look right
Nu> after doing so, don't ya think? yeah I think so
Ot> Nu> Some long text that needs to be wrapped and quoted should look
Ot> Nu> Some long text that needs to be wrapped and quoted should look
Ot> Nu> right after doing so, don't ya think? yeah I think so
*/
@ -498,7 +498,7 @@ Message.prototype.getQuoteLines = function(options, cb) {
tabHandling : 'expand',
tabWidth : 4,
};
return wordWrapText(text, wrapOpts).wrapped.map( (w, i) => {
return i === 0 ? `${quotePrefix}${w}` : `${quotePrefix}${extraPrefix}${w}`;
});
@ -527,44 +527,44 @@ Message.prototype.getQuoteLines = function(options, cb) {
cols : options.cols,
rows : 'auto',
startCol : options.startCol,
forceLineTerm : true,
forceLineTerm : true,
},
(err, prepped) => {
prepped = prepped || this.message;
let lastSgr = '';
const split = splitTextAtTerms(prepped);
const quoteLines = [];
const focusQuoteLines = [];
//
// Do not include quote prefixes (e.g. XX> ) on ANSI replies (and therefor quote builder)
// as while this works in ENiGMA, other boards such as Mystic, WWIV, etc. will try to
// as while this works in ENiGMA, other boards such as Mystic, WWIV, etc. will try to
// strip colors, colorize the lines, etc. If we exclude the prefixes, this seems to do
// the trick and allow them to leave them alone!
//
split.forEach(l => {
quoteLines.push(`${lastSgr}${l}`);
focusQuoteLines.push(`${options.ansiFocusPrefixSgr}>${lastSgr}${renderSubstr(l, 1, l.length - 1)}`);
lastSgr = (l.match(/(?:\x1b\x5b)[\?=;0-9]*m(?!.*(?:\x1b\x5b)[\?=;0-9]*m)/) || [])[0] || ''; // eslint-disable-line no-control-regex
lastSgr = (l.match(/(?:\x1b\x5b)[?=;0-9]*m(?!.*(?:\x1b\x5b)[?=;0-9]*m)/) || [])[0] || ''; // eslint-disable-line no-control-regex
});
quoteLines[quoteLines.length - 1] += options.ansiResetSgr;
return cb(null, quoteLines, focusQuoteLines, true);
}
);
} else {
const QUOTE_RE = /^ ((?:[A-Za-z0-9]{2}\> )+(?:[A-Za-z0-9]{2}\>)*) */;
const QUOTE_RE = /^ ((?:[A-Za-z0-9]{2}> )+(?:[A-Za-z0-9]{2}>)*) */;
const quoted = [];
const input = _.trimEnd(this.message).replace(/\b/g, '');
// find *last* tearline
let tearLinePos = this.getTearLinePosition(input);
tearLinePos = -1 === tearLinePos ? input.length : tearLinePos; // we just want the index or the entire string
input.slice(0, tearLinePos).split(/\r\n\r\n|\n\n/).forEach(paragraph => {
//
// For each paragraph, a state machine:
@ -612,7 +612,7 @@ Message.prototype.getQuoteLines = function(options, cb) {
buf += ` ${line}`;
}
break;
case 'quote_line' :
if(quoteMatch) {
const rem = line.slice(quoteMatch[0].length);
@ -628,7 +628,7 @@ Message.prototype.getQuoteLines = function(options, cb) {
state = 'line';
}
break;
default :
if(isFormattedLine(line)) {
quoted.push(getFormattedLine(line));
@ -637,12 +637,12 @@ Message.prototype.getQuoteLines = function(options, cb) {
buf = 'line' === state ? line : line.replace(/\s/, ''); // trim *first* leading space, if any
}
break;
}
}
});
quoted.push(...getWrapped(buf, quoteMatch ? quoteMatch[1] : null));
});
input.slice(tearLinePos).split(/\r?\n/).forEach(l => {
quoted.push(...getWrapped(l));
});

View File

@ -40,9 +40,9 @@ function getAvailableMessageConferences(client, options) {
options = options || { includeSystemInternal : false };
assert(client || true === options.noClient);
// perform ACS check per conf & omit system_internal if desired
return _.omitBy(Config.messageConferences, (conf, confTag) => {
// perform ACS check per conf & omit system_internal if desired
return _.omitBy(Config.messageConferences, (conf, confTag) => {
if(!options.includeSystemInternal && 'system_internal' === confTag) {
return true;
}
@ -60,15 +60,15 @@ function getSortedAvailMessageConferences(client, options) {
});
sortAreasOrConfs(confs, 'conf');
return confs;
}
// Return an *object* of available areas within |confTag|
function getAvailableMessageAreasByConfTag(confTag, options) {
options = options || {};
// :TODO: confTag === "" then find default
// :TODO: confTag === "" then find default
if(_.has(Config.messageConferences, [ confTag, 'areas' ])) {
const areas = Config.messageConferences[confTag].areas;
@ -92,9 +92,9 @@ function getSortedAvailMessageAreasByConfTag(confTag, options) {
area : v,
};
});
sortAreasOrConfs(areas, 'area');
return areas;
}
@ -103,7 +103,7 @@ function getDefaultMessageConferenceTag(client, disableAcsCheck) {
// Find the first conference marked 'default'. If found,
// inspect |client| against *read* ACS using defaults if not
// specified.
//
//
// If the above fails, just go down the list until we get one
// that passes.
//
@ -116,14 +116,14 @@ function getDefaultMessageConferenceTag(client, disableAcsCheck) {
const conf = Config.messageConferences[defaultConf];
if(true === disableAcsCheck || client.acs.hasMessageConfRead(conf)) {
return defaultConf;
}
}
}
// just use anything we can
defaultConf = _.findKey(Config.messageConferences, (conf, confTag) => {
return 'system_internal' !== confTag && (true === disableAcsCheck || client.acs.hasMessageConfRead(conf));
});
return defaultConf;
}
@ -138,19 +138,19 @@ function getDefaultMessageAreaTagByConfTag(client, confTag, disableAcsCheck) {
confTag = confTag || getDefaultMessageConferenceTag(client);
if(confTag && _.has(Config.messageConferences, [ confTag, 'areas' ])) {
const areaPool = Config.messageConferences[confTag].areas;
const areaPool = Config.messageConferences[confTag].areas;
let defaultArea = _.findKey(areaPool, o => o.default);
if(defaultArea) {
const area = areaPool[defaultArea];
if(true === disableAcsCheck || client.acs.hasMessageAreaRead(area)) {
return defaultArea;
}
}
}
defaultArea = _.findKey(areaPool, (area) => {
return (true === disableAcsCheck || client.acs.hasMessageAreaRead(area));
return (true === disableAcsCheck || client.acs.hasMessageAreaRead(area));
});
return defaultArea;
}
}
@ -159,18 +159,6 @@ function getMessageConferenceByTag(confTag) {
return Config.messageConferences[confTag];
}
function getMessageConfByAreaTag(areaTag) {
const confs = Config.messageConferences;
let conf;
_.forEach(confs, (v) => {
if(_.has(v, [ 'areas', areaTag ])) {
conf = v;
return false; // stop iteration
}
});
return conf;
}
function getMessageConfTagByAreaTag(areaTag) {
const confs = Config.messageConferences;
return Object.keys(confs).find( (confTag) => {
@ -194,9 +182,9 @@ function getMessageAreaByTag(areaTag, optionalConfTag) {
if(_.has(v, [ 'areas', areaTag ])) {
area = v.areas[areaTag];
return false; // stop iteration
}
}
});
return area;
}
}
@ -206,7 +194,7 @@ function changeMessageConference(client, confTag, cb) {
[
function getConf(callback) {
const conf = getMessageConferenceByTag(confTag);
if(conf) {
callback(null, conf);
} else {
@ -216,7 +204,7 @@ function changeMessageConference(client, confTag, cb) {
function getDefaultAreaInConf(conf, callback) {
const areaTag = getDefaultMessageAreaTagByConfTag(client, confTag);
const area = getMessageAreaByTag(areaTag, confTag);
if(area) {
callback(null, conf, { areaTag : areaTag, area : area } );
} else {
@ -229,7 +217,7 @@ function changeMessageConference(client, confTag, cb) {
} else {
return callback(null, conf, areaInfo);
}
},
},
function changeConferenceAndArea(conf, areaInfo, callback) {
const newProps = {
message_conf_tag : confTag,
@ -258,12 +246,12 @@ function changeMessageAreaWithOptions(client, areaTag, options, cb) {
[
function getArea(callback) {
const area = getMessageAreaByTag(areaTag);
return callback(area ? null : new Error('Invalid message areaTag'), area);
return callback(area ? null : new Error('Invalid message areaTag'), area);
},
function validateAccess(area, callback) {
//
// Need at least *read* to access the area
//
//
// Need at least *read* to access the area
//
if(!client.acs.hasMessageAreaRead(area)) {
return callback(new Error('Access denied to message area'));
} else {
@ -294,7 +282,7 @@ function changeMessageAreaWithOptions(client, areaTag, options, cb) {
}
//
// Temporairly -- e.g. non-persisted -- change to an area and it's
// Temporairly -- e.g. non-persisted -- change to an area and it's
// associated underlying conference. ACS is checked for both.
//
// This is useful for example when doing a new scan
@ -312,7 +300,7 @@ function tempChangeMessageConfAndArea(client, areaTag) {
if(!client.acs.hasMessageConfRead(conf) || !client.acs.hasMessageAreaRead(area)) {
return false;
}
client.user.properties.message_conf_tag = confTag;
client.user.properties.message_area_tag = areaTag;
@ -324,7 +312,7 @@ function changeMessageArea(client, areaTag, cb) {
}
function getMessageFromRow(row) {
return {
return {
messageId : row.message_id,
messageUuid : row.message_uuid,
replyToMsgId : row.reply_to_message_id,
@ -346,8 +334,8 @@ function getNewMessageDataInAreaForUserSql(userId, areaTag, lastMessageId, what)
//
// * Only messages > |lastMessageId| should be returned/counted
//
const selectWhat = ('count' === what) ?
'COUNT() AS count' :
const selectWhat = ('count' === what) ?
'COUNT() AS count' :
'message_id, message_uuid, reply_to_message_id, to_user_name, from_user_name, subject, modified_timestamp, view_count';
let sql =
@ -386,7 +374,7 @@ function getNewMessageCountInAreaForUser(userId, areaTag, cb) {
msgDb.get(sql, (err, row) => {
return callback(err, row ? row.count : 0);
});
}
}
],
cb
);
@ -421,7 +409,7 @@ function getNewMessagesInAreaForUser(userId, areaTag, cb) {
function complete(err) {
cb(err, msgList);
}
);
);
}
function getMessageListForArea(options, areaTag, cb) {
@ -435,7 +423,7 @@ function getMessageListForArea(options, areaTag, cb) {
/*
[
{
{
messageId, messageUuid, replyToId, toUserName, fromUserName, subject, modTimestamp,
status(new|old),
viewCount
@ -448,13 +436,13 @@ function getMessageListForArea(options, areaTag, cb) {
async.series(
[
function fetchMessages(callback) {
let sql =
let sql =
`SELECT message_id, message_uuid, reply_to_message_id, to_user_name, from_user_name, subject, modified_timestamp, view_count
FROM message
WHERE area_tag = ?`;
if(Message.isPrivateAreaTag(areaTag)) {
sql +=
sql +=
` AND message_id IN (
SELECT message_id
FROM message_meta
@ -462,7 +450,7 @@ function getMessageListForArea(options, areaTag, cb) {
)`;
}
sql += ' ORDER BY message_id;';
sql += ' ORDER BY message_id;';
msgDb.each(
sql,
@ -551,12 +539,12 @@ function updateMessageAreaLastReadId(userId, areaTag, messageId, allowOlder, cb)
],
function complete(err, didUpdate) {
if(err) {
Log.debug(
{ error : err.toString(), userId : userId, areaTag : areaTag, messageId : messageId },
Log.debug(
{ error : err.toString(), userId : userId, areaTag : areaTag, messageId : messageId },
'Failed updating area last read ID');
} else {
if(true === didUpdate) {
Log.trace(
Log.trace(
{ userId : userId, areaTag : areaTag, messageId : messageId },
'Area last read ID updated');
}
@ -574,7 +562,7 @@ function persistMessage(message, cb) {
},
function recordToMessageNetworks(callback) {
return msgNetRecord(message, callback);
}
}
],
cb
);
@ -582,7 +570,7 @@ function persistMessage(message, cb) {
// method exposed for event scheduler
function trimMessageAreasScheduledEvent(args, cb) {
function trimMessageAreaByMaxMessages(areaInfo, cb) {
if(0 === areaInfo.maxMessages) {
return cb(null);
@ -605,7 +593,7 @@ function trimMessageAreasScheduledEvent(args, cb) {
Log.debug( { areaInfo : areaInfo, type : 'maxMessages', count : this.changes }, 'Area trimmed successfully');
}
return cb(err);
}
}
);
}
@ -690,7 +678,7 @@ function trimMessageAreasScheduledEvent(args, cb) {
trimMessageAreaByMaxAgeDays(areaInfo, err => {
return next(err);
});
});
});
},
callback

View File

@ -36,6 +36,6 @@ function resolveMimeType(query) {
if(mimeTypes.extensions[query]) {
return query; // alreaed a mime-type
}
return mimeTypes.lookup(query) || undefined; // lookup() returns false; we want undefined
}

View File

@ -36,10 +36,10 @@ function resolvePath(path) {
function getCleanEnigmaVersion() {
return packageJson.version
.replace(/\-/g, '.')
.replace(/-/g, '.')
.replace(/alpha/,'a')
.replace(/beta/,'b')
;
;
}
// See also ftn_util.js getTearLine() & getProductIdentifier()

View File

@ -5,7 +5,7 @@ const messageArea = require('../core/message_area.js');
exports.MessageAreaConfTempSwitcher = Sup => class extends Sup {
tempMessageConfAndAreaSwitch(messageAreaTag) {
messageAreaTag = messageAreaTag || this.messageAreaTag;
if(!messageAreaTag) {
@ -14,7 +14,7 @@ exports.MessageAreaConfTempSwitcher = Sup => class extends Sup {
this.prevMessageConfAndArea = {
confTag : this.client.user.properties.message_conf_tag,
areaTag : this.client.user.properties.message_area_tag,
areaTag : this.client.user.properties.message_area_tag,
};
if(!messageArea.tempChangeMessageConfAndArea(this.client, this.messageAreaTag)) {
@ -25,7 +25,7 @@ exports.MessageAreaConfTempSwitcher = Sup => class extends Sup {
tempMessageConfAndAreaRestore() {
if(this.prevMessageConfAndArea) {
this.client.user.properties.message_conf_tag = this.prevMessageConfAndArea.confTag;
this.client.user.properties.message_area_tag = this.prevMessageConfAndArea.areaTag;
this.client.user.properties.message_area_tag = this.prevMessageConfAndArea.areaTag;
}
}
};

View File

@ -36,7 +36,7 @@ exports.moduleInfo = {
const MciViewIds = {
AreaList : 1,
SelAreaInfo1 : 2,
SelAreaInfo2 : 3,
SelAreaInfo2 : 3,
};
exports.getModule = class MessageAreaListModule extends MenuModule {
@ -61,7 +61,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
self.client.term.pipeWrite(`\n|00Cannot change area: ${err.message}\n`);
self.prevMenuOnTimeout(1000, cb);
} else {
} else {
if(_.isString(area.art)) {
const dispOptions = {
client : self.client,
@ -72,7 +72,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
displayThemeArt(dispOptions, () => {
// pause by default, unless explicitly told not to
if(_.has(area, 'options.pause') && false === area.options.pause) {
if(_.has(area, 'options.pause') && false === area.options.pause) {
return self.prevMenuOnTimeout(1000, cb);
} else {
self.pausePrompt( () => {
@ -98,9 +98,9 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
}, timeout);
}
updateGeneralAreaInfoViews(areaIndex) {
// :TODO: these concepts have been replaced with the {someKey} style formatting - update me!
/* experimental: not yet avail
// :TODO: these concepts have been replaced with the {someKey} style formatting - update me!
/*
updateGeneralAreaInfoViews(areaIndex) {
const areaInfo = self.messageAreas[areaIndex];
[ MciViewIds.SelAreaInfo1, MciViewIds.SelAreaInfo2 ].forEach(mciId => {
@ -109,8 +109,8 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
v.setFormatObject(areaInfo.area);
}
});
*/
}
*/
mciReady(mciData, cb) {
super.mciReady(mciData, err => {
@ -137,7 +137,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
function populateAreaListView(callback) {
const listFormat = self.menuConfig.config.listFormat || '{index} ) - {name}';
const focusListFormat = self.menuConfig.config.focusListFormat || listFormat;
const areaListView = vc.getView(MciViewIds.AreaList);
let i = 1;
areaListView.setItems(_.map(self.messageAreas, v => {
@ -145,7 +145,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
index : i++,
areaTag : v.area.areaTag,
name : v.area.name,
desc : v.area.desc,
desc : v.area.desc,
});
}));
@ -155,7 +155,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
index : i++,
areaTag : v.area.areaTag,
name : v.area.name,
desc : v.area.desc,
desc : v.area.desc,
});
}));

View File

@ -48,9 +48,9 @@ exports.getModule = class AreaPostFSEModule extends FullScreenEditorModule {
self.client.log.info(
{ to : msg.toUserName, subject : msg.subject, uuid : msg.uuid },
'Message persisted'
);
);
}
return self.nextMenu(cb);
}
);

View File

@ -69,7 +69,7 @@ exports.getModule = class AreaViewFSEModule extends FullScreenEditorModule {
case 'down arrow' : bodyView.scrollDocumentUp(); break;
case 'up arrow' : bodyView.scrollDocumentDown(); break;
case 'page up' : bodyView.keyPressPageUp(); break;
case 'page down' : bodyView.keyPressPageDown(); break;
case 'page down' : bodyView.keyPressPageDown(); break;
}
// :TODO: need to stop down/page down if doing so would push the last
@ -83,13 +83,13 @@ exports.getModule = class AreaViewFSEModule extends FullScreenEditorModule {
const modOpts = {
extraArgs : {
messageAreaTag : self.messageAreaTag,
replyToMessage : self.message,
}
replyToMessage : self.message,
}
};
return self.gotoMenu(extraArgs.menu, modOpts, cb);
}
self.client.log(extraArgs, 'Missing extraArgs.menu');
return cb(null);
}

View File

@ -21,10 +21,10 @@ exports.moduleInfo = {
const MciViewIds = {
ConfList : 1,
// :TODO:
// # areas in conf .... see Obv/2, iNiQ, ...
//
//
};
exports.getModule = class MessageConfListModule extends MenuModule {
@ -33,16 +33,16 @@ exports.getModule = class MessageConfListModule extends MenuModule {
this.messageConfs = messageArea.getSortedAvailMessageConferences(this.client);
const self = this;
this.menuMethods = {
changeConference : function(formData, extraArgs, cb) {
if(1 === formData.submitId) {
let conf = self.messageConfs[formData.value.conf];
const confTag = conf.confTag;
conf = conf.conf; // what we want is embedded
conf = conf.conf; // what we want is embedded
messageArea.changeMessageConference(self.client, confTag, err => {
if(err) {
if(err) {
self.client.term.pipeWrite(`\n|00Cannot change conference: ${err.message}\n`);
setTimeout( () => {
@ -59,7 +59,7 @@ exports.getModule = class MessageConfListModule extends MenuModule {
displayThemeArt(dispOptions, () => {
// pause by default, unless explicitly told not to
if(_.has(conf, 'options.pause') && false === conf.options.pause) {
if(_.has(conf, 'options.pause') && false === conf.options.pause) {
return self.prevMenuOnTimeout(1000, cb);
} else {
self.pausePrompt( () => {
@ -108,7 +108,7 @@ exports.getModule = class MessageConfListModule extends MenuModule {
function populateConfListView(callback) {
const listFormat = self.menuConfig.config.listFormat || '{index} ) - {name}';
const focusListFormat = self.menuConfig.config.focusListFormat || listFormat;
const confListView = vc.getView(MciViewIds.ConfList);
let i = 1;
confListView.setItems(_.map(self.messageConfs, v => {
@ -116,7 +116,7 @@ exports.getModule = class MessageConfListModule extends MenuModule {
index : i++,
confTag : v.conf.confTag,
name : v.conf.name,
desc : v.conf.desc,
desc : v.conf.desc,
});
}));
@ -126,7 +126,7 @@ exports.getModule = class MessageConfListModule extends MenuModule {
index : i++,
confTag : v.conf.confTag,
name : v.conf.name,
desc : v.conf.desc,
desc : v.conf.desc,
});
}));

View File

@ -26,7 +26,7 @@ const moment = require('moment');
MCI codes:
VM1 : Message list
TL2 : Message info 1: { msgNumSelected, msgNumTotal }
TL2 : Message info 1: { msgNumSelected, msgNumTotal }
*/
exports.moduleInfo = {
@ -84,9 +84,9 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
// due to the size of |messageList|. See https://github.com/trentm/node-bunyan/issues/189
//
modOpts.extraArgs.toJSON = function() {
const logMsgList = (this.messageList.length <= 4) ?
this.messageList :
this.messageList.slice(0, 2).concat(this.messageList.slice(-2));
const logMsgList = (this.messageList.length <= 4) ?
this.messageList :
this.messageList.slice(0, 2).concat(this.messageList.slice(-2));
return {
messageAreaTag : this.messageAreaTag,
@ -158,14 +158,14 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
if(_.isArray(self.messageList)) {
return callback(0 === self.messageList.length ? new Error('No messages in area') : null);
}
messageArea.getMessageListForArea( { client : self.client }, self.messageAreaTag, function msgs(err, msgList) {
if(!msgList || 0 === msgList.length) {
return callback(new Error('No messages in area'));
}
self.messageList = msgList;
return callback(err);
return callback(err);
});
},
function getLastReadMesageId(callback) {
@ -187,15 +187,15 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
if(_.isUndefined(self.initialFocusIndex) && listItem.messageId > self.lastReadId) {
self.initialFocusIndex = index;
}
}
});
return callback(null);
},
function populateList(callback) {
const msgListView = vc.getView(MCICodesIDs.MsgList);
const listFormat = self.menuConfig.config.listFormat || '{msgNum} - {subject} - {toUserName}';
const msgListView = vc.getView(MCICodesIDs.MsgList);
const listFormat = self.menuConfig.config.listFormat || '{msgNum} - {subject} - {toUserName}';
const focusListFormat = self.menuConfig.config.focusListFormat || listFormat; // :TODO: default change color here
const messageInfo1Format = self.menuConfig.config.messageInfo1Format || '{msgNumSelected} / {msgNumTotal}';
const messageInfo1Format = self.menuConfig.config.messageInfo1Format || '{msgNumSelected} / {msgNumTotal}';
// :TODO: This can take a very long time to load large lists. What we need is to implement the "owner draw" concept in
// which items are requested (e.g. their format at least) *as-needed* vs trying to get the format for all of them at once
@ -211,10 +211,10 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
msgListView.on('index update', idx => {
self.setViewText(
'allViews',
MCICodesIDs.MsgInfo1,
MCICodesIDs.MsgInfo1,
stringFormat(messageInfo1Format, { msgNumSelected : (idx + 1), msgNumTotal : self.messageList.length } ));
});
if(self.initialFocusIndex > 0) {
// note: causes redraw()
msgListView.setFocusItemIndex(self.initialFocusIndex);
@ -228,29 +228,29 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
const messageInfo1Format = self.menuConfig.config.messageInfo1Format || '{msgNumSelected} / {msgNumTotal}';
self.setViewText(
'allViews',
MCICodesIDs.MsgInfo1,
MCICodesIDs.MsgInfo1,
stringFormat(messageInfo1Format, { msgNumSelected : self.initialFocusIndex + 1, msgNumTotal : self.messageList.length } ));
return callback(null);
},
],
],
err => {
if(err) {
self.client.log.error( { error : err.message }, 'Error loading message list');
self.client.log.error( { error : err.message }, 'Error loading message list');
}
return cb(err);
}
);
});
});
}
getSaveState() {
return { initialFocusIndex : this.initialFocusIndex };
return { initialFocusIndex : this.initialFocusIndex };
}
restoreSavedState(savedState) {
if(savedState) {
this.initialFocusIndex = savedState.initialFocusIndex;
}
}
}
getMenuResult() {

View File

@ -38,17 +38,17 @@ function startup(cb) {
function shutdown(cb) {
async.each(
msgNetworkModules,
msgNetworkModules,
(msgNetModule, next) => {
msgNetModule.shutdown( () => {
return next();
});
},
},
() => {
msgNetworkModules = [];
return cb(null);
}
);
);
}
function recordMessage(message, cb) {
@ -59,7 +59,7 @@ function recordMessage(message, cb) {
//
async.each(msgNetworkModules, (modInst, next) => {
modInst.record(message);
next();
next();
}, err => {
cb(err);
});

View File

@ -13,12 +13,12 @@ function MessageScanTossModule() {
require('util').inherits(MessageScanTossModule, PluginModule);
MessageScanTossModule.prototype.startup = function(cb) {
cb(null);
return cb(null);
};
MessageScanTossModule.prototype.shutdown = function(cb) {
cb(null);
return cb(null);
};
MessageScanTossModule.prototype.record = function(message) {
MessageScanTossModule.prototype.record = function(/*message*/) {
};

View File

@ -4,7 +4,6 @@
const View = require('./view.js').View;
const strUtil = require('./string_util.js');
const ansi = require('./ansi_term.js');
const colorCodes = require('./color_codes.js');
const wordWrapText = require('./word_wrap.js').wordWrapText;
const ansiPrep = require('./ansi_prep.js');
@ -12,11 +11,11 @@ const assert = require('assert');
const _ = require('lodash');
// :TODO: Determine CTRL-* keys for various things
// See http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/bansi.txt
// http://wiki.synchro.net/howto:editor:slyedit#edit_mode
// http://sublime-text-unofficial-documentation.readthedocs.org/en/latest/reference/keyboard_shortcuts_win.html
// See http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/bansi.txt
// http://wiki.synchro.net/howto:editor:slyedit#edit_mode
// http://sublime-text-unofficial-documentation.readthedocs.org/en/latest/reference/keyboard_shortcuts_win.html
/* Mystic
/* Mystic
[^B] Reformat Paragraph [^O] Show this help file
[^I] Insert tab space [^Q] Enter quote mode
[^K] Cut current line of text [^V] Toggle insert/overwrite
@ -179,8 +178,8 @@ function MultiLineEditTextView(options) {
for(let i = startIndex; i < endIndex; ++i) {
//${self.getSGRFor('text')}
self.client.term.write(
`${ansi.goto(absPos.row++, absPos.col)}${self.getRenderText(i)}`,
self.client.term.write(
`${ansi.goto(absPos.row++, absPos.col)}${self.getRenderText(i)}`,
false // convertLineFeeds
);
}
@ -268,7 +267,7 @@ function MultiLineEditTextView(options) {
if(remain > 0) {
text += ' '.repeat(remain + 1);
// text += new Array(remain + 1).join(' ');
// text += new Array(remain + 1).join(' ');
}
return text;
@ -291,7 +290,7 @@ function MultiLineEditTextView(options) {
lines.forEach(line => {
text += line.text.replace(re, '\t');
if(options.forceLineTerms || (eolMarker && line.eol)) {
text += eolMarker;
}
@ -459,7 +458,7 @@ function MultiLineEditTextView(options) {
self.getRenderText(index).slice(self.cursorPos.col - c.length) +
ansi.goto(absPos.row, absPos.col) +
ansi.showCursor(), false
);
);
}
};
@ -502,7 +501,7 @@ function MultiLineEditTextView(options) {
}
return wordWrapText(
s,
s,
{
width : width,
tabHandling : tabHandling || 'expand',
@ -1122,19 +1121,19 @@ MultiLineEditTextView.prototype.getData = function(options = { forceLineTerms :
MultiLineEditTextView.prototype.setPropertyValue = function(propName, value) {
switch(propName) {
case 'mode' :
case 'mode' :
this.mode = value;
if('preview' === value && !this.specialKeyMap.next) {
this.specialKeyMap.next = [ 'tab' ];
}
}
break;
case 'autoScroll' :
case 'autoScroll' :
this.autoScroll = value;
break;
case 'tabSwitchesView' :
this.tabSwitchesView = value;
this.tabSwitchesView = value;
this.specialKeyMap.next = this.specialKeyMap.next || [];
this.specialKeyMap.next.push('tab');
break;

View File

@ -25,8 +25,8 @@ exports.moduleInfo = {
* :TODO:
* * User configurable new scan: Area selection (avail from messages area) (sep module)
* * Add status TL/VM (either/both should update if present)
* *
* *
*/
const MciCodeIds = {
@ -37,7 +37,7 @@ const MciCodeIds = {
const Steps = {
MessageConfs : 'messageConferences',
FileBase : 'fileBase',
Finished : 'finished',
};
@ -53,7 +53,7 @@ exports.getModule = class NewScanModule extends MenuModule {
// :TODO: Make this conf/area specific:
const config = this.menuConfig.config;
this.scanStartFmt = config.scanStartFmt || 'Scanning {confName} - {areaName}...';
this.scanStartFmt = config.scanStartFmt || 'Scanning {confName} - {areaName}...';
this.scanFinishNoneFmt = config.scanFinishNoneFmt || 'Nothing new';
this.scanFinishNewFmt = config.scanFinishNewFmt || '{count} entries found';
this.scanCompleteMsg = config.scanCompleteMsg || 'Finished newscan';
@ -62,16 +62,16 @@ exports.getModule = class NewScanModule extends MenuModule {
updateScanStatus(statusText) {
this.setViewText('allViews', MciCodeIds.ScanStatusLabel, statusText);
}
newScanMessageConference(cb) {
// lazy init
// lazy init
if(!this.sortedMessageConfs) {
const getAvailOpts = { includeSystemInternal : true }; // find new private messages, bulletins, etc.
const getAvailOpts = { includeSystemInternal : true }; // find new private messages, bulletins, etc.
this.sortedMessageConfs = _.map(msgArea.getAvailableMessageConferences(this.client, getAvailOpts), (v, k) => {
return {
confTag : k,
conf : v,
conf : v,
};
});
@ -91,27 +91,27 @@ exports.getModule = class NewScanModule extends MenuModule {
this.currentScanAux.conf = this.currentScanAux.conf || 0;
this.currentScanAux.area = this.currentScanAux.area || 0;
}
const currentConf = this.sortedMessageConfs[this.currentScanAux.conf];
this.newScanMessageArea(currentConf, () => {
if(this.sortedMessageConfs.length > this.currentScanAux.conf + 1) {
this.currentScanAux.conf += 1;
this.currentScanAux.conf += 1;
this.currentScanAux.area = 0;
return this.newScanMessageConference(cb); // recursive to next conf
}
this.updateScanStatus(this.scanCompleteMsg);
return cb(Errors.DoesNotExist('No more conferences'));
});
});
}
newScanMessageArea(conf, cb) {
// :TODO: it would be nice to cache this - must be done by conf!
// :TODO: it would be nice to cache this - must be done by conf!
const sortedAreas = msgArea.getSortedAvailMessageAreasByConfTag(conf.confTag, { client : this.client } );
const currentArea = sortedAreas[this.currentScanAux.area];
//
// Scan and update index until we find something. If results are found,
// we'll goto the list module & show them.
@ -207,20 +207,20 @@ exports.getModule = class NewScanModule extends MenuModule {
performScanCurrentStep(cb) {
switch(this.currentStep) {
case Steps.MessageConfs :
this.newScanMessageConference( () => {
case Steps.MessageConfs :
this.newScanMessageConference( () => {
this.currentStep = Steps.FileBase;
return this.performScanCurrentStep(cb);
});
break;
case Steps.FileBase :
this.newScanFileBase( () => {
this.currentStep = Steps.Finished;
return this.performScanCurrentStep(cb);
return this.performScanCurrentStep(cb);
});
break;
default : return cb(null);
}
}
@ -241,7 +241,7 @@ exports.getModule = class NewScanModule extends MenuModule {
// :TODO: display scan step/etc.
async.series(
async.series(
[
function loadFromConfig(callback) {
const loadOpts = {

View File

@ -22,10 +22,10 @@ const MciViewIds = {
};
exports.getModule = class NewUserAppModule extends MenuModule {
constructor(options) {
super(options);
const self = this;
this.menuMethods = {
@ -40,7 +40,7 @@ exports.getModule = class NewUserAppModule extends MenuModule {
viewValidationListener : function(err, cb) {
const errMsgView = self.viewControllers.menu.getView(MciViewIds.errMsg);
let newFocusId;
if(err) {
errMsgView.setText(err.message);
err.view.clearText();
@ -67,14 +67,14 @@ exports.getModule = class NewUserAppModule extends MenuModule {
//
// We have to disable ACS checks for initial default areas as the user is not yet ready
//
//
let confTag = messageArea.getDefaultMessageConferenceTag(self.client, true); // true=disableAcsCheck
let areaTag = messageArea.getDefaultMessageAreaTagByConfTag(self.client, confTag, true); // true=disableAcsCheck
// can't store undefined!
confTag = confTag || '';
areaTag = areaTag || '';
newUser.properties = {
real_name : formData.value.realName,
birthdate : new Date(Date.parse(formData.value.birthdate)).toISOString(), // :TODO: Use moment & explicit ISO string format
@ -84,12 +84,12 @@ exports.getModule = class NewUserAppModule extends MenuModule {
email_address : formData.value.email,
web_address : formData.value.web,
account_created : new Date().toISOString(), // :TODO: Use moment & explicit ISO string format
message_conf_tag : confTag,
message_area_tag : areaTag,
term_height : self.client.term.termHeight,
term_width : self.client.term.termWidth,
term_width : self.client.term.termWidth,
// :TODO: Other defaults
// :TODO: should probably have a place to create defaults/etc.
@ -100,7 +100,7 @@ exports.getModule = class NewUserAppModule extends MenuModule {
} else {
newUser.properties.theme_id = Config.defaults.theme;
}
// :TODO: User.create() should validate email uniqueness!
newUser.create(formData.value.password, err => {
if(err) {

View File

@ -20,7 +20,7 @@ const async = require('async');
const _ = require('lodash');
const moment = require('moment');
/*
/*
Module :TODO:
* Add pipe code support
- override max length & monitor *display* len as user types in order to allow for actual display len with color
@ -73,7 +73,7 @@ exports.getModule = class OnelinerzModule extends MenuModule {
self.client.log.warn( { error : err.message }, 'Failed saving oneliner');
}
self.clearAddForm();
self.clearAddForm();
return self.displayViewScreen(true, cb); // true=cls
});
@ -89,7 +89,7 @@ exports.getModule = class OnelinerzModule extends MenuModule {
}
};
}
initSequence() {
const self = this;
async.series(
@ -136,7 +136,7 @@ exports.getModule = class OnelinerzModule extends MenuModule {
function initOrRedrawViewController(artData, callback) {
if(_.isUndefined(self.viewControllers.add)) {
const vc = self.addViewController(
'view',
'view',
new ViewController( { client : self.client, formId : FormIds.View } )
);
@ -149,7 +149,7 @@ exports.getModule = class OnelinerzModule extends MenuModule {
return vc.loadFromMenuConfig(loadOpts, callback);
} else {
self.viewControllers.view.setFocus(true);
self.viewControllers.view.getView(MciViewIds.ViewForm.AddPrompt).redraw();
self.viewControllers.view.getView(MciViewIds.ViewForm.AddPrompt).redraw();
return callback(null);
}
},
@ -216,7 +216,7 @@ exports.getModule = class OnelinerzModule extends MenuModule {
[
function clearAndDisplayArt(callback) {
self.viewControllers.view.setFocus(false);
self.client.term.rawWrite(ansi.resetScreen());
self.client.term.rawWrite(ansi.resetScreen());
theme.displayThemedAsset(
self.menuConfig.config.art.add,
@ -230,7 +230,7 @@ exports.getModule = class OnelinerzModule extends MenuModule {
function initOrRedrawViewController(artData, callback) {
if(_.isUndefined(self.viewControllers.add)) {
const vc = self.addViewController(
'add',
'add',
new ViewController( { client : self.client, formId : FormIds.Add } )
);
@ -269,7 +269,7 @@ exports.getModule = class OnelinerzModule extends MenuModule {
[
function openDatabase(callback) {
self.db = getTransactionDatabase(new sqlite3.Database(
getModDatabasePath(exports.moduleInfo),
getModDatabasePath(exports.moduleInfo),
err => {
return callback(err);
}
@ -284,10 +284,10 @@ exports.getModule = class OnelinerzModule extends MenuModule {
oneliner VARCHAR NOT NULL,
timestamp DATETIME NOT NULL
);`
,
err => {
return callback(err);
});
,
err => {
return callback(err);
});
}
],
err => {
@ -327,7 +327,7 @@ exports.getModule = class OnelinerzModule extends MenuModule {
err => {
return cb(err);
}
);
);
}
beforeArt(cb) {

View File

@ -3,5 +3,5 @@
exports.PluginModule = PluginModule;
function PluginModule(options) {
function PluginModule(/*options*/) {
}

View File

@ -92,7 +92,7 @@ const PREDEFINED_MCI_GENERATORS = {
ST : function serverName(client) { return client.session.serverName; },
FN : function activeFileBaseFilterName(client) {
const activeFilter = FileBaseFilters.getActiveFilter(client);
return activeFilter ? activeFilter.name : '';
return activeFilter ? activeFilter.name : '';
},
DN : function userNumDownloads(client) { return userStatAsString(client, 'dl_total_count', 0); }, // Obv/2
DK : function userByteDownload(client) { // Obv/2 uses DK=downloaded Kbytes
@ -160,7 +160,7 @@ const PREDEFINED_MCI_GENERATORS = {
},
OA : function systemArchitecture() { return os.arch(); },
SC : function systemCpuModel() {
//
// Clean up CPU strings a bit for better display
@ -190,7 +190,7 @@ const PREDEFINED_MCI_GENERATORS = {
// System File Base, Up/Download Info
//
// :TODO: DD - Today's # of downloads (iNiQUiTY)
//
//
SD : function systemNumDownloads() { return sysStatAsString('dl_total_count', 0); },
SO : function systemByteDownload() {
const byteSize = StatLog.getSystemStatNum('dl_total_bytes');
@ -221,7 +221,7 @@ const PREDEFINED_MCI_GENERATORS = {
// -> Include FTN/etc.
// :TODO: LC - name of last caller to system (Obv/2)
// :TODO: TZ - Average *system* post/call ratio (iNiQUiTY)
//
// Special handling for XY

View File

@ -52,9 +52,9 @@ exports.getModule = class RumorzModule extends MenuModule {
addEntry : (formData, extraArgs, cb) => {
if(_.isString(formData.value.rumor) && renderStringLength(formData.value.rumor) > 0) {
const rumor = formData.value.rumor.trim(); // remove any trailing ws
StatLog.appendSystemLogEntry(STATLOG_KEY_RUMORZ, rumor, StatLog.KeepDays.Forever, StatLog.KeepType.Forever, () => {
this.clearAddForm();
this.clearAddForm();
return this.displayViewScreen(true, cb); // true=cls
});
} else {
@ -77,7 +77,7 @@ exports.getModule = class RumorzModule extends MenuModule {
const previewView = this.viewControllers.add.getView(MciCodeIds.AddForm.EntryPreview);
newEntryView.setText('');
// preview is optional
if(previewView) {
previewView.setText('');
@ -130,7 +130,7 @@ exports.getModule = class RumorzModule extends MenuModule {
function initOrRedrawViewController(artData, callback) {
if(_.isUndefined(self.viewControllers.add)) {
const vc = self.addViewController(
'view',
'view',
new ViewController( { client : self.client, formId : FormIds.View } )
);
@ -143,7 +143,7 @@ exports.getModule = class RumorzModule extends MenuModule {
return vc.loadFromMenuConfig(loadOpts, callback);
} else {
self.viewControllers.view.setFocus(true);
self.viewControllers.view.getView(MciCodeIds.ViewForm.AddPrompt).redraw();
self.viewControllers.view.getView(MciCodeIds.ViewForm.AddPrompt).redraw();
return callback(null);
}
},
@ -186,7 +186,7 @@ exports.getModule = class RumorzModule extends MenuModule {
[
function clearAndDisplayArt(callback) {
self.viewControllers.view.setFocus(false);
self.client.term.rawWrite(resetScreen());
self.client.term.rawWrite(resetScreen());
theme.displayThemedAsset(
self.config.art.add,
@ -200,7 +200,7 @@ exports.getModule = class RumorzModule extends MenuModule {
function initOrRedrawViewController(artData, callback) {
if(_.isUndefined(self.viewControllers.add)) {
const vc = self.addViewController(
'add',
'add',
new ViewController( { client : self.client, formId : FormIds.Add } )
);
@ -220,7 +220,7 @@ exports.getModule = class RumorzModule extends MenuModule {
},
function initPreviewUpdates(callback) {
const previewView = self.viewControllers.add.getView(MciCodeIds.AddForm.EntryPreview);
const entryView = self.viewControllers.add.getView(MciCodeIds.AddForm.NewEntry);
const entryView = self.viewControllers.add.getView(MciCodeIds.AddForm.NewEntry);
if(previewView) {
let timerId;
entryView.on('key press', () => {
@ -230,7 +230,7 @@ exports.getModule = class RumorzModule extends MenuModule {
if(focused === entryView) {
previewView.setText(entryView.getData());
focused.setFocus(true);
}
}
}, 500);
});
}

View File

@ -8,7 +8,9 @@ exports.readSAUCE = readSAUCE;
const SAUCE_SIZE = 128;
const SAUCE_ID = new Buffer([0x53, 0x41, 0x55, 0x43, 0x45]); // 'SAUCE'
const COMNT_ID = new Buffer([0x43, 0x4f, 0x4d, 0x4e, 0x54]); // 'COMNT'
// :TODO read comments
//const COMNT_ID = new Buffer([0x43, 0x4f, 0x4d, 0x4e, 0x54]); // 'COMNT'
exports.SAUCE_SIZE = SAUCE_SIZE;
// :TODO: SAUCE should be a class
@ -51,7 +53,7 @@ function readSAUCE(data, cb) {
if(!SAUCE_ID.equals(vars.id)) {
return cb(new Error('No SAUCE record present'));
}
}
var ver = iconv.decode(vars.version, 'cp437');
@ -137,7 +139,7 @@ var SAUCE_FONT_TO_ENCODING_HINT = {
};
['437', '720', '737', '775', '819', '850', '852', '855', '857', '858',
'860', '861', '862', '863', '864', '865', '866', '869', '872'].forEach(function onPage(page) {
'860', '861', '862', '863', '864', '865', '866', '869', '872'].forEach(function onPage(page) {
var codec = 'cp' + page;
SAUCE_FONT_TO_ENCODING_HINT['IBM EGA43 ' + page] = codec;
SAUCE_FONT_TO_ENCODING_HINT['IBM EGA ' + page] = codec;

View File

@ -1213,7 +1213,30 @@ function FTNMessageScanTossModule() {
User.getUserIdAndNameByLookup(lookupName, (err, localToUserId, localUserName) => {
if(err) {
return callback(Errors.DoesNotExist(`Could not get local user ID for "${message.toUserName}": ${err.message}`));
//
// Couldn't find a local username. If the toUserName itself is a FTN address
// we can only assume the message is to the +op, else we'll have to fail.
//
const toUserNameAsAddress = Address.fromString(message.toUserName);
if(toUserNameAsAddress.isValid()) {
Log.info(
{ toUserName : message.toUserName, fromUserName : message.fromUserName },
'No local "to" username for FTN message. Appears to be a FTN address only; assuming addressed to SysOp'
);
User.getUserName(User.RootUserID, (err, sysOpUserName) => {
if(err) {
return callback(Errors.UnexpectedState('Failed to get SysOp user information'));
}
message.meta.System[Message.SystemMetaNames.LocalToUserID] = User.RootUserID;
message.toUserName = sysOpUserName;
return callback(null);
});
} else {
return callback(Errors.DoesNotExist(`Could not get local user ID for "${message.toUserName}": ${err.message}`));
}
}
// we do this after such that error cases can be preseved above

View File

@ -43,7 +43,7 @@ exports.getModule = class SetNewScanDate extends MenuModule {
const config = this.menuConfig.config;
this.target = config.target || 'message';
this.scanDateFormat = config.scanDateFormat || 'YYYYMMDD';
this.scanDateFormat = config.scanDateFormat || 'YYYYMMDD';
this.menuMethods = {
scanDateSubmit : (formData, extraArgs, cb) => {
@ -232,7 +232,7 @@ exports.getModule = class SetNewScanDate extends MenuModule {
const scanDateView = vc.getView(MciViewIds.main.scanDate);
// :TODO: MaskTextEditView needs some love: If setText() with input that matches the mask, we should ignore the non-mask chars! Hack in place for now
const scanDateFormat = self.scanDateFormat.replace(/[\/\-. ]/g, '');
const scanDateFormat = self.scanDateFormat.replace(/[/\-. ]/g, '');
scanDateView.setText(today.format(scanDateFormat));
if('message' === self.target) {

View File

@ -1,13 +1,12 @@
/* jslint node: true */
'use strict';
var MenuView = require('./menu_view.js').MenuView;
var ansi = require('./ansi_term.js');
var strUtil = require('./string_util.js');
const MenuView = require('./menu_view.js').MenuView;
const ansi = require('./ansi_term.js');
const strUtil = require('./string_util.js');
var util = require('util');
var assert = require('assert');
var _ = require('lodash');
const util = require('util');
const assert = require('assert');
exports.SpinnerMenuView = SpinnerMenuView;
@ -16,7 +15,7 @@ function SpinnerMenuView(options) {
options.cursor = options.cursor || 'hide';
MenuView.call(this, options);
var self = this;
/*
@ -29,7 +28,7 @@ function SpinnerMenuView(options) {
//assert(!self.positionCacheExpired);
assert(this.focusedItemIndex >= 0 && this.focusedItemIndex <= self.items.length);
self.drawItem(this.focusedItemIndex);
};
@ -66,19 +65,19 @@ SpinnerMenuView.prototype.setFocus = function(focused) {
SpinnerMenuView.prototype.setFocusItemIndex = function(index) {
SpinnerMenuView.super_.prototype.setFocusItemIndex.call(this, index); // sets this.focusedItemIndex
this.updateSelection(); // will redraw
};
SpinnerMenuView.prototype.onKeyPress = function(ch, key) {
if(key) {
if(this.isKeyMapped('up', key.name)) {
if(this.isKeyMapped('up', key.name)) {
if(0 === this.focusedItemIndex) {
this.focusedItemIndex = this.items.length - 1;
} else {
this.focusedItemIndex--;
}
this.updateSelection();
return;
} else if(this.isKeyMapped('down', key.name)) {
@ -87,7 +86,7 @@ SpinnerMenuView.prototype.onKeyPress = function(ch, key) {
} else {
this.focusedItemIndex++;
}
this.updateSelection();
return;
}

View File

@ -10,14 +10,14 @@ const moment = require('moment');
/*
System Event Log & Stats
------------------------
System & user specific:
* Events for generating various statistics, logs such as last callers, etc.
* Stats such as counters
User specific stats are simply an alternate interface to user properties, while
system wide entries are handled on their own. Both are read accessible non-blocking
making them easily available for MCI codes for example.
making them easily available for MCI codes for example.
*/
class StatLog {
constructor() {
@ -66,7 +66,7 @@ class StatLog {
TimestampDesc : 'timestamp_desc',
Random : 'random',
};
}
}
setNonPeristentSystemStat(statName, statValue) {
this.systemStats[statName] = statValue;
@ -139,7 +139,7 @@ class StatLog {
return cb(new Error(`Value for ${statName} is not a number!`));
}
newValue += incrementBy;
newValue += incrementBy;
} else {
newValue = incrementBy;
}
@ -201,19 +201,19 @@ class StatLog {
}
}
);
break;
break;
case 'forever' :
default :
// nop
break;
}
}
}
);
}
getSystemLogEntries(logName, order, limit, cb) {
let sql =
let sql =
`SELECT timestamp, log_value
FROM system_event_log
WHERE log_name = ?`;
@ -228,7 +228,7 @@ class StatLog {
sql += ' ORDER BY timestamp DESC';
break;
case 'random' :
case 'random' :
sql += ' ORDER BY RANDOM()';
}
@ -279,7 +279,7 @@ class StatLog {
);
}
);
}
}
}
module.exports = new StatLog();

View File

@ -1,30 +0,0 @@
/* jslint node: true */
'use strict';
var userDb = require('./database.js').dbs.user;
exports.getSystemLoginHistory = getSystemLoginHistory;
function getSystemLoginHistory(numRequested, cb) {
numRequested = Math.max(1, numRequested);
var loginHistory = [];
userDb.each(
'SELECT user_id, user_name, timestamp ' +
'FROM user_login_history ' +
'ORDER BY timestamp DESC ' +
'LIMIT ' + numRequested + ';',
function historyRow(err, histEntry) {
loginHistory.push( {
userId : histEntry.user_id,
userName : histEntry.user_name,
timestamp : histEntry.timestamp,
} );
},
function complete(err, recCount) {
cb(err, loginHistory);
}
);
}

View File

@ -1,64 +0,0 @@
/* jslint node: true */
'use strict';
var View = require('./view.js').View;
var TextView = require('./text_view.js').TextView;
var assert = require('assert');
var _ = require('lodash');
function StatusBarView(options) {
View.call(this, options);
var self = this;
}
require('util').inherits(StatusBarView, View);
StatusBarView.prototype.redraw = function() {
StatusBarView.super_.prototype.redraw.call(this);
};
StatusBarView.prototype.setPanels = function(panels) {
/*
"panels" : [
{
"text" : "things and stuff",
"width" 20,
...
},
{
"width" : 40 // no text, etc... = spacer
}
]
|---------------------------------------------|
| stuff |
*/
assert(_.isArray(panels));
this.panels = [];
var tvOpts = {
cursor : 'hide',
position : { row : this.position.row, col : 0 },
};
panels.forEach(function panel(p) {
assert(_.isObject(p));
assert(_.has(p, 'width'));
if(p.text) {
this.panels.push( new TextView( { }))
} else {
this.panels.push( { width : p.width } );
}
});
};

View File

@ -5,7 +5,7 @@ const EnigError = require('./enig_error.js').EnigError;
const {
pad,
stylizeString,
stylizeString,
renderStringLength,
renderSubstr,
formatByteSize, formatByteSizeAbbr,
@ -172,15 +172,15 @@ function formatNumberHelper(n, precision, type) {
case 'b' : return n.toString(2);
case 'o' : return n.toString(8);
case 'x' : return n.toString(16);
case 'e' : return n.toExponential(precision).replace(FormatNumRegExp.ExponentRep, '$&0');
case 'f' : return n.toFixed(precision);
case 'e' : return n.toExponential(precision).replace(FormatNumRegExp.ExponentRep, '$&0');
case 'f' : return n.toFixed(precision);
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');
default :
throw new ValueError(`Unknown format code "${type}" for object of type 'float'`);
}
@ -207,7 +207,7 @@ function formatNumber(value, tokens) {
if('' !== tokens.precision) {
throw new ValueError('Precision not allowed in integer format specifier');
}
}
} else if( [ 'e', 'E', 'f', 'F', 'g', 'G', '%' ].indexOf(type) > - 1) {
if(tokens['#']) {
throw new ValueError('Alternate form (#) not allowed in float format specifier');
@ -215,7 +215,7 @@ function formatNumber(value, tokens) {
}
const s = formatNumberHelper(Math.abs(value), Number(tokens.precision || 6), type);
const sign = value < 0 || 1 / value < 0 ?
const sign = value < 0 || 1 / value < 0 ?
'-' :
'-' === tokens.sign ? '' : tokens.sign;
@ -223,7 +223,7 @@ function formatNumber(value, tokens) {
if(tokens[',']) {
const match = /^(\d*)(.*)$/.exec(s);
const separated = match[1].replace(/.(?=(...)+$)/g, '$&,') + match[2];
const separated = match[1].replace(/.(?=(...)+$)/g, '$&,') + match[2];
if('=' !== align) {
return pad(sign + separated, width, fill, getPadAlign(align));
@ -246,7 +246,7 @@ function formatNumber(value, tokens) {
if(0 === width) {
return sign + prefix + s;
}
}
if('=' === align) {
return sign + prefix + pad(s, width - sign.length - prefix.length, fill, getPadAlign('>'));
@ -272,9 +272,9 @@ const transformers = {
styleL33t : (s) => stylizeString(s, 'l33t'),
// :TODO:
// toMegs(), toKilobytes(), ...
// toList(), toCommaList(),
// toMegs(), toKilobytes(), ...
// toList(), toCommaList(),
sizeWithAbbr : (n) => formatByteSize(n, true, 2),
sizeWithoutAbbr : (n) => formatByteSize(n, false, 2),
sizeAbbr : (n) => formatByteSizeAbbr(n),
@ -293,14 +293,14 @@ function transformValue(transformerName, value) {
}
// :TODO: Use explicit set of chars for paths & function/transforms such that } is allowed as fill/etc.
const REGEXP_BASIC_FORMAT = /{([^.!:}]+(?:\.[^.!:}]+)*)(?:\!([^:}]+))?(?:\:([^}]+))?}/g;
const REGEXP_BASIC_FORMAT = /{([^.!:}]+(?:\.[^.!:}]+)*)(?:!([^:}]+))?(?::([^}]+))?}/g;
function getValue(obj, path) {
const value = _.get(obj, path);
if(!_.isUndefined(value)) {
return _.isFunction(value) ? value() : value;
}
throw new KeyError(quote(path));
}
@ -350,7 +350,7 @@ module.exports = function format(fmt, obj) {
// remainder
if(pos < fmt.length) {
out += fmt.slice(pos);
}
}
return out;
return out;
};

View File

@ -3,7 +3,6 @@
// ENiGMA½
const miscUtil = require('./misc_util.js');
const ANSIEscapeParser = require('./ansi_escape_parser.js').ANSIEscapeParser;
const ANSI = require('./ansi_term.js');
// deps
@ -53,12 +52,12 @@ function stylizeString(s, style) {
switch(style) {
// None/normal
case 'normal' :
case 'N' :
case 'N' :
return s;
// UPPERCASE
case 'upper' :
case 'U' :
case 'upper' :
case 'U' :
return s.toUpperCase();
// lowercase
@ -107,8 +106,8 @@ function stylizeString(s, style) {
return stylized;
// Small i's: DEMENTiA
case 'small i' :
case 'i' :
case 'small i' :
case 'i' :
return s.toUpperCase().replace(/I/g, 'i');
// mIxeD CaSE (random upper/lower)
@ -128,7 +127,7 @@ function stylizeString(s, style) {
case '3' :
for(i = 0; i < len; ++i) {
c = SIMPLE_ELITE_MAP[s[i].toLowerCase()];
stylized += c || s[i];
stylized += c || s[i];
}
return stylized;
}
@ -147,11 +146,11 @@ function pad(s, len, padChar, dir, stringSGR, padSGR, useRenderLen) {
useRenderLen = miscUtil.valueWithDefault(useRenderLen, true);
const renderLen = useRenderLen ? renderStringLength(s) : s.length;
const padlen = len >= renderLen ? len - renderLen : 0;
const padlen = len >= renderLen ? len - renderLen : 0;
switch(dir) {
case 'L' :
case 'left' :
case 'left' :
s = padSGR + new Array(padlen).join(padChar) + stringSGR + s;
break;
@ -162,10 +161,10 @@ function pad(s, len, padChar, dir, stringSGR, padSGR, useRenderLen) {
const right = Math.ceil(padlen / 2);
const left = padlen - right;
s = padSGR + new Array(left + 1).join(padChar) + stringSGR + s + padSGR + new Array(right + 1).join(padChar);
}
}
break;
case 'R' :
case 'R' :
case 'right' :
s = stringSGR + s + padSGR + new Array(padlen).join(padChar);
break;
@ -184,7 +183,7 @@ function replaceAt(s, n, t) {
return s.substring(0, n) + t + s.substring(n + 1);
}
const RE_NON_PRINTABLE =
const RE_NON_PRINTABLE =
/[\0-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/; // eslint-disable-line no-control-regex
function isPrintable(s) {
@ -198,11 +197,6 @@ function isPrintable(s) {
return !RE_NON_PRINTABLE.test(s);
}
function stringLength(s) {
// :TODO: See https://mathiasbynens.be/notes/javascript-unicode
return s.length;
}
function stripAllLineFeeds(s) {
return s.replace(/\r?\n|[\r\u2028\u2029]/g, '');
}
@ -256,7 +250,7 @@ function renderSubstr(str, start, length) {
match = re.exec(str);
if(match) {
if(match.index > pos) {
if(match.index > pos) {
s = str.slice(pos + start, Math.min(match.index, pos + (length - renderLen)));
start = 0; // start offset applies only once
out += s;
@ -269,7 +263,7 @@ function renderSubstr(str, start, length) {
// remainder
if(pos + start < str.length && renderLen < length) {
out += str.slice(pos + start, (pos + start + (length - renderLen)));
out += str.slice(pos + start, (pos + start + (length - renderLen)));
//out += str.slice(pos + start, Math.max(1, pos + (length - renderLen - 1)));
}
@ -277,7 +271,7 @@ function renderSubstr(str, start, length) {
}
//
// Method to return the "rendered" length taking into account Pipe and ANSI color codes.
// Method to return the "rendered" length taking into account Pipe and ANSI color codes.
//
// We additionally account for ANSI *forward* movement ESC sequences
// in the form of ESC[<N>C where <N> is the "go forward" character count.
@ -291,40 +285,40 @@ function renderStringLength(s) {
const re = ANSI_OR_PIPE_REGEXP;
re.lastIndex = 0; // we recycle the rege; reset
//
// Loop counting only literal (non-control) sequences
// paying special attention to ESC[<N>C which means forward <N>
//
//
do {
pos = re.lastIndex;
m = re.exec(s);
if(m) {
if(m.index > pos) {
len += s.slice(pos, m.index).length;
}
if('C' === m[3]) { // ESC[<N>C is foward/right
len += parseInt(m[2], 10) || 0;
}
}
}
} while(0 !== re.lastIndex);
if(pos < s.length) {
len += s.slice(pos).length;
}
return len;
}
const BYTE_SIZE_ABBRS = [ 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' ]; // :)
const BYTE_SIZE_ABBRS = [ 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' ]; // :)
function formatByteSizeAbbr(byteSize) {
if(0 === byteSize) {
return BYTE_SIZE_ABBRS[0]; // B
}
return BYTE_SIZE_ABBRS[Math.floor(Math.log(byteSize) / Math.log(1024))];
}
@ -332,7 +326,7 @@ function formatByteSize(byteSize, withAbbr = false, decimals = 2) {
const i = 0 === byteSize ? byteSize : Math.floor(Math.log(byteSize) / Math.log(1024));
let result = parseFloat((byteSize / Math.pow(1024, i)).toFixed(decimals));
if(withAbbr) {
result += ` ${BYTE_SIZE_ABBRS[i]}`;
result += ` ${BYTE_SIZE_ABBRS[i]}`;
}
return result;
}
@ -351,7 +345,7 @@ function formatCount(count, withAbbr = false, decimals = 2) {
const i = 0 === count ? count : Math.floor(Math.log(count) / Math.log(1000));
let result = parseFloat((count / Math.pow(1000, i)).toFixed(decimals));
if(withAbbr) {
result += `${COUNT_ABBRS[i]}`;
result += `${COUNT_ABBRS[i]}`;
}
return result;
}
@ -359,7 +353,7 @@ function formatCount(count, withAbbr = false, decimals = 2) {
// :TODO: See notes in word_wrap.js about need to consolidate the various ANSI related RegExp's
//const REGEXP_ANSI_CONTROL_CODES = /(\x1b\x5b)([\?=;0-9]*?)([0-9A-ORZcf-npsu=><])/g;
const REGEXP_ANSI_CONTROL_CODES = /(?:\x1b\x5b)([\?=;0-9]*?)([A-ORZcf-npsu=><])/g; // eslint-disable-line no-control-regex
const REGEXP_ANSI_CONTROL_CODES = /(?:\x1b\x5b)([?=;0-9]*?)([A-ORZcf-npsu=><])/g; // eslint-disable-line no-control-regex
const ANSI_OPCODES_ALLOWED_CLEAN = [
//'A', 'B', // up, down
//'C', 'D', // right, left
@ -370,17 +364,17 @@ function cleanControlCodes(input, options) {
let m;
let pos;
let cleaned = '';
options = options || {};
//
// Loop through |input| adding only allowed ESC
// sequences and literals to |cleaned|
//
//
do {
pos = REGEXP_ANSI_CONTROL_CODES.lastIndex;
m = REGEXP_ANSI_CONTROL_CODES.exec(input);
if(m) {
if(m.index > pos) {
cleaned += input.slice(pos, m.index);
@ -394,205 +388,17 @@ function cleanControlCodes(input, options) {
cleaned += m[0];
}
}
} while(0 !== REGEXP_ANSI_CONTROL_CODES.lastIndex);
// remainder
if(pos < input.length) {
cleaned += input.slice(pos);
}
return cleaned;
}
function prepAnsi(input, options, cb) {
if(!input) {
return cb(null, '');
}
options.termWidth = options.termWidth || 80;
options.termHeight = options.termHeight || 25;
options.cols = options.cols || options.termWidth || 80;
options.rows = options.rows || options.termHeight || 'auto';
options.startCol = options.startCol || 1;
options.exportMode = options.exportMode || false;
const canvas = Array.from( { length : 'auto' === options.rows ? 25 : options.rows }, () => Array.from( { length : options.cols}, () => new Object() ) );
const parser = new ANSIEscapeParser( { termHeight : options.termHeight, termWidth : options.termWidth } );
const state = {
row : 0,
col : 0,
};
let lastRow = 0;
function ensureRow(row) {
if(Array.isArray(canvas[row])) {
return;
}
canvas[row] = Array.from( { length : options.cols}, () => new Object() );
}
parser.on('position update', (row, col) => {
state.row = row - 1;
state.col = col - 1;
lastRow = Math.max(state.row, lastRow);
});
parser.on('literal', literal => {
//
// CR/LF are handled for 'position update'; we don't need the chars themselves
//
literal = literal.replace(/\r?\n|[\r\u2028\u2029]/g, '');
for(let c of literal) {
if(state.col < options.cols && ('auto' === options.rows || state.row < options.rows)) {
ensureRow(state.row);
canvas[state.row][state.col].char = c;
if(state.sgr) {
canvas[state.row][state.col].sgr = state.sgr;
state.sgr = null;
}
}
state.col += 1;
}
});
parser.on('control', (match, opCode) => {
//
// Movement is handled via 'position update', so we really only care about
// display opCodes
//
switch(opCode) {
case 'm' :
state.sgr = (state.sgr || '') + match;
break;
default :
break;
}
});
function getLastPopulatedColumn(row) {
let col = row.length;
while(--col > 0) {
if(row[col].char || row[col].sgr) {
break;
}
}
return col;
}
parser.on('complete', () => {
let output = '';
let lastSgr = '';
let line;
canvas.slice(0, lastRow + 1).forEach(row => {
const lastCol = getLastPopulatedColumn(row) + 1;
let i;
line = '';
for(i = 0; i < lastCol; ++i) {
const col = row[i];
if(col.sgr) {
lastSgr = col.sgr;
}
line += `${col.sgr || ''}${col.char || ' '}`;
}
output += line;
if(i < row.length) {
output += `${ANSI.blackBG()}${row.slice(i).map( () => ' ').join('')}${lastSgr}`;
}
//if(options.startCol + options.cols < options.termWidth || options.forceLineTerm) {
if(options.startCol + i < options.termWidth || options.forceLineTerm) {
output += '\r\n';
}
});
if(options.exportMode) {
//
// If we're in export mode, we do some additional hackery:
//
// * Hard wrap ALL lines at <= 79 *characters* (not visible columns)
// if a line must wrap early, we'll place a ESC[A ESC[<N>C where <N>
// represents chars to get back to the position we were previously at
//
// * Replace contig spaces with ESC[<N>C as well to save... space.
//
// :TODO: this would be better to do as part of the processing above, but this will do for now
const MAX_CHARS = 79 - 8; // 79 max, - 8 for max ESC seq's we may prefix a line with
let exportOutput = '';
let m;
let afterSeq;
let wantMore;
let renderStart;
splitTextAtTerms(output).forEach(fullLine => {
renderStart = 0;
while(fullLine.length > 0) {
let splitAt;
const ANSI_REGEXP = ANSI.getFullMatchRegExp();
wantMore = true;
while((m = ANSI_REGEXP.exec(fullLine))) {
afterSeq = m.index + m[0].length;
if(afterSeq < MAX_CHARS) {
// after current seq
splitAt = afterSeq;
} else {
if(m.index < MAX_CHARS) {
// before last found seq
splitAt = m.index;
wantMore = false; // can't eat up any more
}
break; // seq's beyond this point are >= MAX_CHARS
}
}
if(splitAt) {
if(wantMore) {
splitAt = Math.min(fullLine.length, MAX_CHARS - 1);
}
} else {
splitAt = Math.min(fullLine.length, MAX_CHARS - 1);
}
const part = fullLine.slice(0, splitAt);
fullLine = fullLine.slice(splitAt);
renderStart += renderStringLength(part);
exportOutput += `${part}\r\n`;
if(fullLine.length > 0) { // more to go for this line?
exportOutput += `${ANSI.up()}${ANSI.right(renderStart)}`;
} else {
exportOutput += ANSI.up();
}
}
});
return cb(null, exportOutput);
}
return cb(null, output);
});
parser.parse(input);
}
function isAnsiLine(line) {
return isAnsi(line);// || renderStringLength(line) < line.length;
}
@ -622,22 +428,23 @@ function isFormattedLine(line) {
return false;
}
// :TODO: rename to containsAnsi()
function isAnsi(input) {
if(!input || 0 === input.length) {
return false;
}
//
// * ANSI found - limited, just colors
// * Full ANSI art
// *
//
// *
//
// FULL ANSI art:
// * SAUCE present & reports as ANSI art
// * ANSI clear screen within first 2-3 codes
// * ANSI movement codes (goto, right, left, etc.)
//
// *
//
// *
/*
readSAUCE(input, (err, sauce) => {
if(!err && ('ANSi' === sauce.fileType || 'ANSiMation' === sauce.fileType)) {
@ -647,8 +454,8 @@ function isAnsi(input) {
*/
// :TODO: if a similar method is kept, use exec() until threshold
const ANSI_DET_REGEXP = /(?:\x1b\x5b)[\?=;0-9]*?[ABCDEFGHJKLMSTfhlmnprsu]/g; // eslint-disable-line no-control-regex
const m = input.match(ANSI_DET_REGEXP) || [];
const ANSI_DET_REGEXP = /(?:\x1b\x5b)[?=;0-9]*?[ABCDEFGHJKLMSTfhlmnprsu]/g; // eslint-disable-line no-control-regex
const m = input.match(ANSI_DET_REGEXP) || [];
return m.length >= 4; // :TODO: do this reasonably, e.g. a percent or soemthing
}

View File

@ -33,7 +33,7 @@ function login(callingMenu, formData, extraArgs, cb) {
return callingMenu.prevMenu(cb);
}
}
// success!
return callingMenu.nextMenu(cb);
});
@ -72,7 +72,7 @@ function prevMenu(callingMenu, formData, extraArgs, cb) {
callingMenu.prevMenu( err => {
if(err) {
callingMenu.client.log.error( { error : err.message }, 'Error attempting to fallback!');
callingMenu.client.log.error( { error : err.message }, 'Error attempting to fallback!');
}
return cb(err);
});
@ -119,7 +119,7 @@ function nextConf(callingMenu, formData, extraArgs, cb) {
if(err) {
return cb(err); // logged within changeMessageConference()
}
return reloadMenu(callingMenu, cb);
});
}
@ -132,7 +132,7 @@ function prevArea(callingMenu, formData, extraArgs, cb) {
if(err) {
return cb(err); // logged within changeMessageArea()
}
return reloadMenu(callingMenu, cb);
});
}
@ -155,10 +155,10 @@ function nextArea(callingMenu, formData, extraArgs, cb) {
}
function sendForgotPasswordEmail(callingMenu, formData, extraArgs, cb) {
const username = formData.value.username || callingMenu.client.user.username;
const username = formData.value.username || callingMenu.client.user.username;
const WebPasswordReset = require('./web_password_reset.js').WebPasswordReset;
WebPasswordReset.sendForgotPasswordEmail(username, err => {
if(err) {
callingMenu.client.log.warn( { err : err.message }, 'Failed sending forgot password email');
@ -166,8 +166,8 @@ function sendForgotPasswordEmail(callingMenu, formData, extraArgs, cb) {
if(extraArgs.next) {
return callingMenu.gotoMenu(extraArgs.next, cb);
}
return logoff(callingMenu, formData, extraArgs, cb);
}
return logoff(callingMenu, formData, extraArgs, cb);
});
}

View File

@ -99,7 +99,7 @@ function validateGeneralMailAddressedTo(data, cb) {
function validateEmailAvail(data, cb) {
//
// This particular method allows empty data - e.g. no email entered
//
//
if(!data || 0 === data.length) {
return cb(null);
}
@ -110,7 +110,7 @@ function validateEmailAvail(data, cb) {
//
// See http://stackoverflow.com/questions/7786058/find-the-regex-used-by-html5-forms-for-validation
//
const emailRegExp = /[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9-]+(.[a-z0-9-]+)*/;
const emailRegExp = /[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(.[a-z0-9-]+)*/;
if(!emailRegExp.test(data)) {
return cb(new Error('Invalid email address'));
}
@ -121,8 +121,8 @@ function validateEmailAvail(data, cb) {
} else if(uids.length > 0) {
return cb(new Error('Email address not unique'));
}
return cb(null);
return cb(null);
});
}

View File

@ -42,7 +42,7 @@ class TelnetClientConnection extends EventEmitter {
this.client = client;
}
restorePipe() {
if(!this.pipeRestored) {
this.pipeRestored = true;
@ -68,14 +68,14 @@ class TelnetClientConnection extends EventEmitter {
this.bridgeConnection.on('data', data => {
this.client.term.rawWrite(data);
//
//
// Wait for a terminal type request, and send it eactly once.
// This is enough (in additional to other negotiations handled in telnet.js)
// to get us in on most systems
//
if(!this.termSent && data.indexOf(IAC_DO_TERM_TYPE) > -1) {
this.termSent = true;
this.bridgeConnection.write(this.getTermTypeNegotiationBuffer());
this.bridgeConnection.write(this.getTermTypeNegotiationBuffer());
}
});
@ -102,9 +102,9 @@ class TelnetClientConnection extends EventEmitter {
// actual/current terminal type.
//
let bufs = buffers();
bufs.push(new Buffer(
[
[
255, // IAC
250, // SB
24, // TERMINAL-TYPE
@ -113,9 +113,9 @@ class TelnetClientConnection extends EventEmitter {
));
bufs.push(
new Buffer(this.client.term.termType), // e.g. "ansi"
new Buffer(this.client.term.termType), // e.g. "ansi"
new Buffer( [ 255, 240 ] ) // IAC, SE
);
);
return bufs.toBuffer();
}
@ -128,9 +128,9 @@ exports.getModule = class TelnetBridgeModule extends MenuModule {
this.config = options.menuConfig.config;
// defaults
this.config.port = this.config.port || 23;
this.config.port = this.config.port || 23;
}
initSequence() {
let clientTerminated;
const self = this;
@ -158,7 +158,7 @@ exports.getModule = class TelnetBridgeModule extends MenuModule {
self.client.term.write(` Connecting to ${connectOpts.host}, please wait...\n`);
const telnetConnection = new TelnetClientConnection(self.client);
telnetConnection.on('connected', () => {
self.client.log.info(connectOpts, 'Telnet bridge connection established');

View File

@ -35,7 +35,7 @@ function TextView(options) {
this.justify = options.justify || 'right';
this.resizable = miscUtil.valueWithDefault(options.resizable, true);
this.horizScroll = miscUtil.valueWithDefault(options.horizScroll, true);
if(_.isString(options.textOverflow)) {
this.textOverflow = options.textOverflow;
}
@ -44,19 +44,19 @@ function TextView(options) {
this.textMaskChar = options.textMaskChar;
}
/*
/*
this.drawText = function(s) {
//
//
// |<- this.maxLength
// ABCDEFGHIJK
// |ABCDEFG| ^_ this.text.length
// ^-- this.dimens.width
//
let textToDraw = _.isString(this.textMaskChar) ?
new Array(s.length + 1).join(this.textMaskChar) :
let textToDraw = _.isString(this.textMaskChar) ?
new Array(s.length + 1).join(this.textMaskChar) :
stylizeString(s, this.hasFocus ? this.focusTextStyle : this.textStyle);
if(textToDraw.length > this.dimens.width) {
if(this.hasFocus) {
if(this.horizScroll) {
@ -64,7 +64,7 @@ function TextView(options) {
}
} else {
if(textToDraw.length > this.dimens.width) {
if(this.textOverflow &&
if(this.textOverflow &&
this.dimens.width > this.textOverflow.length &&
textToDraw.length - this.textOverflow.length >= this.textOverflow.length)
{
@ -72,7 +72,7 @@ function TextView(options) {
} else {
textToDraw = textToDraw.substr(0, this.dimens.width);
}
}
}
}
}
@ -89,7 +89,7 @@ function TextView(options) {
this.drawText = function(s) {
//
//
// |<- this.maxLength
// ABCDEFGHIJK
// |ABCDEFG| ^_ this.text.length
@ -97,26 +97,26 @@ function TextView(options) {
//
let renderLength = renderStringLength(s); // initial; may be adjusted below:
let textToDraw = _.isString(this.textMaskChar) ?
new Array(renderLength + 1).join(this.textMaskChar) :
let textToDraw = _.isString(this.textMaskChar) ?
new Array(renderLength + 1).join(this.textMaskChar) :
stylizeString(s, this.hasFocus ? this.focusTextStyle : this.textStyle);
renderLength = renderStringLength(textToDraw);
if(renderLength >= this.dimens.width) {
if(this.hasFocus) {
if(this.horizScroll) {
textToDraw = renderSubstr(textToDraw, renderLength - this.dimens.width, renderLength);
}
} else {
if(this.textOverflow &&
if(this.textOverflow &&
this.dimens.width > this.textOverflow.length &&
renderLength - this.textOverflow.length >= this.textOverflow.length)
{
textToDraw = renderSubstr(textToDraw, 0, this.dimens.width - this.textOverflow.length) + this.textOverflow;
textToDraw = renderSubstr(textToDraw, 0, this.dimens.width - this.textOverflow.length) + this.textOverflow;
} else {
textToDraw = renderSubstr(textToDraw, 0, this.dimens.width);
}
}
}
}
@ -128,7 +128,7 @@ function TextView(options) {
this.justify,
this.hasFocus ? this.getFocusSGR() : this.getSGR(),
this.getStyleSGR(1) || this.getSGR()
),
),
false // no converting CRLF needed
);
};
@ -136,7 +136,7 @@ function TextView(options) {
this.getEndOfTextColumn = function() {
var offset = Math.min(this.text.length, this.dimens.width);
return this.position.col + offset;
return this.position.col + offset;
};
this.setText(options.text || '', false); // false=do not redraw now
@ -168,7 +168,7 @@ TextView.prototype.setFocus = function(focused) {
TextView.super_.prototype.setFocus.call(this, focused);
this.redraw();
this.client.term.write(ansi.goto(this.position.row, this.getEndOfTextColumn()));
this.client.term.write(this.getFocusSGR());
};
@ -184,7 +184,7 @@ TextView.prototype.setText = function(text, redraw) {
text = text.toString();
}
text = pipeToAnsi(stripAllLineFeeds(text), this.client); // expand MCI/etc.
text = pipeToAnsi(stripAllLineFeeds(text), this.client); // expand MCI/etc.
var widthDelta = 0;
if(this.text && this.text !== text) {
@ -199,7 +199,7 @@ TextView.prototype.setText = function(text, redraw) {
}
// :TODO: it would be nice to be able to stylize strings with MCI and {special} MCI syntax, e.g. "|BN {UN!toUpper}"
this.text = stylizeString(this.text, this.hasFocus ? this.focusTextStyle : this.textStyle);
this.text = stylizeString(this.text, this.hasFocus ? this.focusTextStyle : this.textStyle);
if(this.autoScale.width) {
this.dimens.width = renderStringLength(this.text) + widthDelta;
@ -214,7 +214,7 @@ TextView.prototype.setText = function(text, redraw) {
TextView.prototype.setText = function(text) {
if(!_.isString(text)) {
text = text.toString();
}
}
var widthDelta = 0;
if(this.text && this.text !== text) {
@ -227,7 +227,7 @@ TextView.prototype.setText = function(text) {
this.text = this.text.substr(0, this.maxLength);
}
this.text = stylizeString(this.text, this.hasFocus ? this.focusTextStyle : this.textStyle);
this.text = stylizeString(this.text, this.hasFocus ? this.focusTextStyle : this.textStyle);
//if(this.resizable) {
// this.dimens.width = this.text.length + widthDelta;
@ -254,9 +254,9 @@ TextView.prototype.setPropertyValue = function(propName, value) {
if(true === value) {
this.textMaskChar = this.client.currentTheme.helpers.getPasswordChar();
}
break;
break;
}
TextView.super_.prototype.setPropertyValue.call(this, propName, value);
};

View File

@ -87,8 +87,8 @@ function loadTheme(themeID, cb) {
if(err) {
return cb(err);
}
if(!_.isObject(theme.info) ||
if(!_.isObject(theme.info) ||
!_.isString(theme.info.name) ||
!_.isString(theme.info.author))
{
@ -114,16 +114,16 @@ const IMMUTABLE_MCI_PROPERTIES = [
function getMergedTheme(menuConfig, promptConfig, theme) {
assert(_.isObject(menuConfig));
assert(_.isObject(theme));
// :TODO: merge in defaults (customization.defaults{} )
// :TODO: apply generic stuff, e.g. "VM" (vs "VM1")
//
// Create a *clone* of menuConfig (menu.hjson) then bring in
// promptConfig (prompt.hjson)
//
// :TODO: merge in defaults (customization.defaults{} )
// :TODO: apply generic stuff, e.g. "VM" (vs "VM1")
//
// Create a *clone* of menuConfig (menu.hjson) then bring in
// promptConfig (prompt.hjson)
//
var mergedTheme = _.cloneDeep(menuConfig);
if(_.isObject(promptConfig.prompts)) {
mergedTheme.prompts = _.cloneDeep(promptConfig.prompts);
}
@ -136,8 +136,8 @@ function getMergedTheme(menuConfig, promptConfig, theme) {
//
// merge customizer to disallow immutable MCI properties
//
var mciCustomizer = function(objVal, srcVal, key) {
//
var mciCustomizer = function(objVal, srcVal, key) {
return IMMUTABLE_MCI_PROPERTIES.indexOf(key) > -1 ? objVal : srcVal;
};
@ -159,69 +159,69 @@ function getMergedTheme(menuConfig, promptConfig, theme) {
} else {
if(_.has(src, [ formKey, 'mci' ])) {
mergeMciProperties(dest, src[formKey].mci);
}
}
}
}
//
// menu.hjson can have a couple different structures:
// 1) Explicit declaration of expected MCI code(s) under 'form:<id>' before a 'mci' block
// (this allows multiple layout types defined by one menu for example)
//
// 2) Non-explicit declaration: 'mci' directly under 'form:<id>'
//
// theme.hjson has it's own mix:
// 1) Explicit: Form ID before 'mci' (generally used where there are > 1 forms)
//
// 2) Non-explicit: 'mci' directly under an entry
//
// Additionally, #1 or #2 may be under an explicit key of MCI code(s) to match up
// with menu.hjson in #1.
//
// * When theming an explicit menu.hjson entry (1), we will use a matching explicit
// entry with a matching MCI code(s) key in theme.hjson (e.g. menu="ETVM"/theme="ETVM"
// and fall back to generic if a match is not found.
//
// * If theme.hjson provides form ID's, use them. Otherwise, we'll apply directly assuming
// there is a generic 'mci' block.
//
function applyToForm(form, menuTheme, formKey) {
//
// menu.hjson can have a couple different structures:
// 1) Explicit declaration of expected MCI code(s) under 'form:<id>' before a 'mci' block
// (this allows multiple layout types defined by one menu for example)
//
// 2) Non-explicit declaration: 'mci' directly under 'form:<id>'
//
// theme.hjson has it's own mix:
// 1) Explicit: Form ID before 'mci' (generally used where there are > 1 forms)
//
// 2) Non-explicit: 'mci' directly under an entry
//
// Additionally, #1 or #2 may be under an explicit key of MCI code(s) to match up
// with menu.hjson in #1.
//
// * When theming an explicit menu.hjson entry (1), we will use a matching explicit
// entry with a matching MCI code(s) key in theme.hjson (e.g. menu="ETVM"/theme="ETVM"
// and fall back to generic if a match is not found.
//
// * If theme.hjson provides form ID's, use them. Otherwise, we'll apply directly assuming
// there is a generic 'mci' block.
//
function applyToForm(form, menuTheme, formKey) {
if(_.isObject(form.mci)) {
// non-explicit: no MCI code(s) key assumed since we found 'mci' directly under form ID
applyThemeMciBlock(form.mci, menuTheme, formKey);
} else {
var menuMciCodeKeys = _.remove(_.keys(form), function pred(k) {
return k === k.toUpperCase(); // remove anything not uppercase
return k === k.toUpperCase(); // remove anything not uppercase
});
menuMciCodeKeys.forEach(function mciKeyEntry(mciKey) {
var applyFrom;
var applyFrom;
if(_.has(menuTheme, [ mciKey, 'mci' ])) {
applyFrom = menuTheme[mciKey];
} else {
applyFrom = menuTheme;
}
applyThemeMciBlock(form[mciKey].mci, applyFrom);
});
}
}
[ 'menus', 'prompts' ].forEach(function areaEntry(sectionName) {
_.keys(mergedTheme[sectionName]).forEach(function menuEntry(menuName) {
var createdFormSection = false;
var mergedThemeMenu = mergedTheme[sectionName][menuName];
if(_.has(theme, [ 'customization', sectionName, menuName ])) {
var menuTheme = theme.customization[sectionName][menuName];
// config block is direct assign/overwrite
// :TODO: should probably be _.merge()
if(menuTheme.config) {
mergedThemeMenu.config = _.assign(mergedThemeMenu.config || {}, menuTheme.config);
}
if('menus' === sectionName) {
if(_.isObject(mergedThemeMenu.form)) {
getFormKeys(mergedThemeMenu.form).forEach(function formKeyEntry(formKey) {
@ -232,7 +232,7 @@ function getMergedTheme(menuConfig, promptConfig, theme) {
//
// Not specified at menu level means we apply anything from the
// theme to form.0.mci{}
//
//
mergedThemeMenu.form = { 0 : { mci : { } } };
mergeMciProperties(mergedThemeMenu.form[0], menuTheme);
createdFormSection = true;
@ -241,9 +241,9 @@ function getMergedTheme(menuConfig, promptConfig, theme) {
} else if('prompts' === sectionName) {
// no 'form' or form keys for prompts -- direct to mci
applyToForm(mergedThemeMenu, menuTheme);
}
}
}
//
// Finished merging for this menu/prompt
//
@ -259,13 +259,13 @@ function getMergedTheme(menuConfig, promptConfig, theme) {
}
});
});
return mergedTheme;
}
function initAvailableThemes(cb) {
async.waterfall(
[
function loadMenuConfig(callback) {
@ -285,9 +285,9 @@ function initAvailableThemes(cb) {
}
return callback(
null,
menuConfig,
promptConfig,
null,
menuConfig,
promptConfig,
files.filter( f => {
// sync normally not allowed -- initAvailableThemes() is a startup-only method, however
return fs.statSync(paths.join(Config.paths.themes, f)).isDirectory();
@ -363,7 +363,7 @@ function setClientTheme(client, themeId) {
logMsg = 'Failed setting theme by system default ID; Using the first one we can find';
}
}
client.log.debug( { themeId : themeId, info : client.currentTheme.info }, logMsg);
}
@ -371,7 +371,7 @@ function getThemeArt(options, cb) {
//
// options - required:
// name
//
//
// options - optional
// client - needed for user's theme/etc.
// themeId
@ -388,7 +388,7 @@ function getThemeArt(options, cb) {
// :TODO: replace asAnsi stuff with something like retrieveAs = 'ansi' | 'pipe' | ...
// :TODO: Some of these options should only be set if not provided!
options.asAnsi = true; // always convert to ANSI
options.readSauce = true; // read SAUCE, if avail
options.readSauce = true; // read SAUCE, if avail
options.random = _.get(options, 'random', true); // FILENAME<n>.EXT support
//
@ -406,7 +406,7 @@ function getThemeArt(options, cb) {
//
if('/' === options.name.charAt(0)) {
// just take the path as-is
options.basePath = paths.dirname(options.name);
options.basePath = paths.dirname(options.name);
} else if(options.name.indexOf('/') > -1) {
// make relative to base BBS dir
options.basePath = paths.join(__dirname, '../', paths.dirname(options.name));
@ -432,7 +432,7 @@ function getThemeArt(options, cb) {
if(artInfo || Config.defaults.theme === options.themeId) {
return callback(null, artInfo);
}
options.basePath = paths.join(Config.paths.themes, Config.defaults.theme);
art.getArt(options.name, options, (err, artInfo) => {
return callback(null, artInfo);
@ -442,11 +442,11 @@ function getThemeArt(options, cb) {
if(artInfo) {
return callback(null, artInfo);
}
options.basePath = Config.paths.art;
art.getArt(options.name, options, (err, artInfo) => {
return callback(err, artInfo);
});
});
}
],
function complete(err, artInfo) {
@ -483,7 +483,7 @@ function displayThemeArt(options, cb) {
/*
function displayThemedPrompt(name, client, options, cb) {
async.waterfall(
[
function loadConfig(callback) {
@ -511,14 +511,14 @@ function displayThemedPrompt(name, client, options, cb) {
//
// If we did not clear the screen, don't let the font change
//
//
const dispOptions = Object.assign( {}, promptConfig.options );
if(!options.clearScreen) {
dispOptions.font = 'not_really_a_font!';
}
displayThemedAsset(
promptConfig.art,
promptConfig.art,
client,
dispOptions,
(err, artData) => {
@ -576,7 +576,7 @@ function displayThemedPrompt(name, client, options, cb) {
}
displayThemedAsset(
promptConfig.art,
promptConfig.art,
client,
dispOptions,
(err, artInfo) => {
@ -593,7 +593,7 @@ function displayThemedPrompt(name, client, options, cb) {
// no need to query cursor - we're not gonna use it
return callback(null, promptConfig, artInfo);
}
client.once('cursor position report', pos => {
artInfo.startRow = pos[0] - artInfo.height;
return callback(null, promptConfig, artInfo);
@ -627,7 +627,7 @@ function displayThemedPrompt(name, client, options, cb) {
if(options.clearPrompt) {
if(artInfo.startRow && artInfo.height) {
client.term.rawWrite(ansi.goto(artInfo.startRow, 1));
// Note: Does not work properly in NetRunner < 2.0b17:
client.term.rawWrite(ansi.deleteLine(artInfo.height));
} else {
@ -654,7 +654,7 @@ function displayThemedPrompt(name, client, options, cb) {
//
// Pause prompts are a special prompt by the name 'pause'.
//
//
function displayThemedPause(client, options, cb) {
if(!cb && _.isFunction(options)) {
@ -699,7 +699,7 @@ function displayThemedAsset(assetSpec, client, options, cb) {
});
break;
case 'method' :
case 'method' :
// :TODO: fetch & render via method
break;

View File

@ -28,7 +28,7 @@ module.exports = class TicFileInfo {
static get requiredFields() {
return [
'Area', 'Origin', 'From', 'File', 'Crc',
'Area', 'Origin', 'From', 'File', 'Crc',
// :TODO: validate this:
//'Path', 'Seenby' // these two are questionable; some systems don't send them?
];
@ -43,16 +43,16 @@ module.exports = class TicFileInfo {
if(value) {
//
// We call toString() on values to ensure numbers, addresses, etc. are converted
//
//
joinWith = joinWith || '';
if(Array.isArray(value)) {
return value.map(v => v.toString() ).join(joinWith);
}
return value.toString();
}
}
get filePath() {
return paths.join(paths.dirname(this.path), this.getAsString('File'));
}
@ -86,7 +86,7 @@ module.exports = class TicFileInfo {
const localInfo = {
areaTag : config.localAreaTags.find( areaTag => areaTag.toUpperCase() === area ),
};
if(!localInfo.areaTag) {
return callback(Errors.Invalid(`No local area for "Area" of ${area}`));
}
@ -112,7 +112,7 @@ module.exports = class TicFileInfo {
return callback(null, localInfo);
},
function checksumAndSize(localInfo, callback) {
const crcTic = self.get('Crc');
const crcTic = self.get('Crc');
const stream = fs.createReadStream(self.filePath);
const crc = new CRC32();
let sizeActual = 0;
@ -193,7 +193,7 @@ module.exports = class TicFileInfo {
// This is an optional keyword."
//
const to = this.get('To');
if(!to) {
return allowNonExplicit;
}
@ -219,10 +219,10 @@ module.exports = class TicFileInfo {
let key;
let value;
let entry;
lines.forEach(line => {
keyEnd = line.search(/\s/);
if(keyEnd < 0) {
keyEnd = line.length;
}
@ -253,7 +253,7 @@ module.exports = class TicFileInfo {
value = parseInt(value, 16);
break;
case 'size' :
case 'size' :
value = parseInt(value, 10);
break;

View File

@ -1,94 +0,0 @@
/* jslint node: true */
'use strict';
var View = require('./view.js').View;
var miscUtil = require('./misc_util.js');
var strUtil = require('./string_util.js');
var ansi = require('./ansi_term.js');
var util = require('util');
var assert = require('assert');
exports.TickerTextView = TickerTextView;
function TickerTextView(options) {
View.call(this, options);
var self = this;
this.text = options.text || '';
this.tickerStyle = options.tickerStyle || 'rightToLeft';
assert(this.tickerStyle in TickerTextView.TickerStyles);
// :TODO: Ticker |text| should have ANSI stripped before calculating any lengths/etc.
// strUtil.ansiTextLength(s)
// strUtil.pad(..., ignoreAnsi)
// strUtil.stylizeString(..., ignoreAnsi)
this.tickerState = {};
switch(this.tickerStyle) {
case 'rightToLeft' :
this.tickerState.pos = this.position.row + this.dimens.width;
break;
}
self.onTickerInterval = function() {
switch(self.tickerStyle) {
case 'rightToLeft' : self.updateRightToLeftTicker(); break;
}
};
self.updateRightToLeftTicker = function() {
// if pos < start
// drawRemain()
// if pos + remain > end
// drawRemain(0, spaceFor)
// else
// drawString() + remainPading
};
}
util.inherits(TickerTextView, View);
TickerTextView.TickerStyles = {
leftToRight : 1,
rightToLeft : 2,
bounce : 3,
slamLeft : 4,
slamRight : 5,
slamBounce : 6,
decrypt : 7,
typewriter : 8,
};
Object.freeze(TickerTextView.TickerStyles);
/*
TickerTextView.TICKER_STYLES = [
'leftToRight',
'rightToLeft',
'bounce',
'slamLeft',
'slamRight',
'slamBounce',
'decrypt',
'typewriter',
];
*/
TickerTextView.prototype.controllerAttached = function() {
// :TODO: call super
};
TickerTextView.prototype.controllerDetached = function() {
// :TODO: call super
};
TickerTextView.prototype.setText = function(text) {
this.text = strUtil.stylizeString(text, this.textStyle);
if(!this.dimens || !this.dimens.width) {
this.dimens.width = Math.ceil(this.text.length / 2);
}
};

View File

@ -1,13 +1,11 @@
/* jslint node: true */
'use strict';
var MenuView = require('./menu_view.js').MenuView;
var ansi = require('./ansi_term.js');
var strUtil = require('./string_util.js');
const MenuView = require('./menu_view.js').MenuView;
const strUtil = require('./string_util.js');
var util = require('util');
var assert = require('assert');
var _ = require('lodash');
const util = require('util');
const assert = require('assert');
exports.ToggleMenuView = ToggleMenuView;
@ -44,7 +42,7 @@ ToggleMenuView.prototype.redraw = function() {
var item = this.items[i];
var text = strUtil.stylizeString(
item.text, i === this.focusedItemIndex && this.hasFocus ? this.focusTextStyle : this.textStyle);
if(1 === i) {
//console.log(this.styleColor1)
//var sepColor = this.getANSIColor(this.styleColor1 || this.getColor());

View File

@ -85,7 +85,7 @@ exports.getModule = class UploadModule extends MenuModule {
fileDetailsContinue : (formData, extraArgs, cb) => {
// see displayFileDetailsPageForUploadEntry() for this hackery:
cb(null);
cb(null);
return this.fileDetailsCurrentEntrySubmitCallback(null, formData.value); // move on to the next entry, if any
},
@ -119,7 +119,7 @@ exports.getModule = class UploadModule extends MenuModule {
return cb(null);
}
};
};
}
getSaveState() {
@ -143,12 +143,12 @@ exports.getModule = class UploadModule extends MenuModule {
isBlindUpload() { return 'blind' === this.uploadType; }
isFileTransferComplete() { return !_.isUndefined(this.recvFilePaths); }
initSequence() {
const self = this;
if(0 === this.availAreas.length) {
//
//
return this.gotoMenu(this.menuConfig.config.noUploadAreasAvailMenu || 'fileBaseNoUploadAreasAvail');
}
@ -185,7 +185,7 @@ exports.getModule = class UploadModule extends MenuModule {
// need a terminator for various external protocols
this.tempRecvDirectory = pathWithTerminatingSeparator(tempRecvDirectory);
const modOpts = {
extraArgs : {
recvDirectory : this.tempRecvDirectory, // we'll move files from here to their area container once processed/confirmed
@ -203,8 +203,8 @@ exports.getModule = class UploadModule extends MenuModule {
// Upon completion, we'll re-enter the module with some file paths handed to us
//
return this.gotoMenu(
this.menuConfig.config.fileTransferProtocolSelection || 'fileTransferProtocolSelection',
modOpts,
this.menuConfig.config.fileTransferProtocolSelection || 'fileTransferProtocolSelection',
modOpts,
cb
);
});
@ -219,7 +219,7 @@ exports.getModule = class UploadModule extends MenuModule {
const fmtObj = Object.assign( {}, stepInfo);
let stepIndicatorFmt = '';
let logStepFmt;
let logStepFmt;
const fmtConfig = this.menuConfig.config;
@ -228,7 +228,7 @@ exports.getModule = class UploadModule extends MenuModule {
const indicator = { };
const self = this;
function updateIndicator(mci, isFinished) {
indicator.mci = mci;
@ -253,7 +253,7 @@ exports.getModule = class UploadModule extends MenuModule {
updateIndicator(MciViewIds.processing.calcHashIndicator);
break;
case 'hash_finish' :
case 'hash_finish' :
stepIndicatorFmt = fmtConfig.calcHashCompleteFormat || 'Finished calculating hash/checksums';
updateIndicator(MciViewIds.processing.calcHashIndicator, true);
break;
@ -263,7 +263,7 @@ exports.getModule = class UploadModule extends MenuModule {
updateIndicator(MciViewIds.processing.archiveListIndicator);
break;
case 'archive_list_finish' :
case 'archive_list_finish' :
fmtObj.archivedFileCount = stepInfo.archiveEntries.length;
stepIndicatorFmt = fmtConfig.extractArchiveListFinishFormat || 'Archive list extracted ({archivedFileCount} files)';
updateIndicator(MciViewIds.processing.archiveListIndicator, true);
@ -273,7 +273,7 @@ exports.getModule = class UploadModule extends MenuModule {
stepIndicatorFmt = fmtConfig.extractArchiveListFailedFormat || 'Archive list extraction failed';
break;
case 'desc_files_start' :
case 'desc_files_start' :
stepIndicatorFmt = fmtConfig.processingDescFilesFormat || 'Processing description files';
updateIndicator(MciViewIds.processing.descFileIndicator);
break;
@ -289,7 +289,7 @@ exports.getModule = class UploadModule extends MenuModule {
}
fmtObj.stepIndicatorText = stringFormat(stepIndicatorFmt, fmtObj);
if(this.hasProcessingArt) {
this.updateCustomViewTextsWithFilter('processing', MciViewIds.processing.customRangeStart, fmtObj, { appendMultiLine : true } );
@ -339,7 +339,7 @@ exports.getModule = class UploadModule extends MenuModule {
return nextScanStep(null);
}
self.client.log.debug('Scanning file', { filePath : filePath } );
self.client.log.debug('Scanning file', { filePath : filePath } );
scanFile(filePath, scanOpts, handleScanStep, (err, fileEntry, dupeEntries) => {
if(err) {
@ -389,7 +389,7 @@ exports.getModule = class UploadModule extends MenuModule {
// name changed; ajust before persist
newEntry.fileName = paths.basename(finalPath);
}
return nextEntry(null); // still try next file
}
@ -474,7 +474,7 @@ exports.getModule = class UploadModule extends MenuModule {
if(err) {
return nextDupe(err);
}
const areaInfo = getFileAreaByTag(dupe.areaTag);
if(areaInfo) {
dupe.areaName = areaInfo.name;
@ -553,12 +553,12 @@ exports.getModule = class UploadModule extends MenuModule {
return callback(null, scanResults);
}
return self.displayDupesPage(scanResults.dupes, () => {
return self.displayDupesPage(scanResults.dupes, () => {
return callback(null, scanResults);
});
},
function prepDetails(scanResults, callback) {
return self.prepDetailsForUpload(scanResults, callback);
return self.prepDetailsForUpload(scanResults, callback);
},
function startMovingAndPersistingToDatabase(scanResults, callback) {
//
@ -583,14 +583,14 @@ exports.getModule = class UploadModule extends MenuModule {
displayOptionsPage(cb) {
const self = this;
async.series(
[
function prepArtAndViewController(callback) {
return self.prepViewControllerWithArt(
'options',
FormIds.options,
{ clearScreen : true, trailingLF : false },
'options',
FormIds.options,
{ clearScreen : true, trailingLF : false },
callback
);
},
@ -621,7 +621,7 @@ exports.getModule = class UploadModule extends MenuModule {
fileNameView.setText(sanatizeFilename(fileNameView.getData()));
}
});
self.uploadType = 'blind';
uploadTypeView.setFocusItemIndex(0); // default to blind
fileNameView.setText(blindFileNameText);
@ -658,14 +658,14 @@ exports.getModule = class UploadModule extends MenuModule {
displayFileDetailsPageForUploadEntry(fileEntry, cb) {
const self = this;
async.waterfall(
[
function prepArtAndViewController(callback) {
return self.prepViewControllerWithArt(
'fileDetails',
'fileDetails',
FormIds.fileDetails,
{ clearScreen : true, trailingLF : false },
{ clearScreen : true, trailingLF : false },
err => {
return callback(err);
}

Some files were not shown because too many files have changed in this diff Show More