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

View File

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

View File

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

View File

@ -4,7 +4,7 @@
// ENiGMA½ // ENiGMA½
const ANSIEscapeParser = require('./ansi_escape_parser.js').ANSIEscapeParser; const ANSIEscapeParser = require('./ansi_escape_parser.js').ANSIEscapeParser;
const ANSI = require('./ansi_term.js'); const ANSI = require('./ansi_term.js');
const { const {
splitTextAtTerms, splitTextAtTerms,
renderStringLength renderStringLength
} = require('./string_util.js'); } = require('./string_util.js');
@ -41,7 +41,7 @@ module.exports = function ansiPrep(input, options, cb) {
if(canvas[row]) { if(canvas[row]) {
return; return;
} }
canvas[row] = Array.from( { length : options.cols}, () => new Object() ); 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; const lastCol = getLastPopulatedColumn(row) + 1;
let i; let i;
line = options.indent ? line = options.indent ?
output.length > 0 ? ' '.repeat(options.indent) : '' : output.length > 0 ? ' '.repeat(options.indent) : '' :
''; '';
for(i = 0; i < lastCol; ++i) { for(i = 0; i < lastCol; ++i) {
const col = row[i]; const col = row[i];
sgr = !options.asciiMode && 0 === i ? sgr = !options.asciiMode && 0 === i ?
col.initialSgr ? ANSI.getSGRFromGraphicRendition(col.initialSgr) : '' : col.initialSgr ? ANSI.getSGRFromGraphicRendition(col.initialSgr) : '' :
''; '';
if(!options.asciiMode && col.sgr) { if(!options.asciiMode && col.sgr) {
sgr += ANSI.getSGRFromGraphicRendition(col.sgr); sgr += ANSI.getSGRFromGraphicRendition(col.sgr);
} }
@ -148,7 +148,7 @@ module.exports = function ansiPrep(input, options, cb) {
if(options.exportMode) { if(options.exportMode) {
// //
// If we're in export mode, we do some additional hackery: // If we're in export mode, we do some additional hackery:
// //
// * Hard wrap ALL lines at <= 79 *characters* (not visible columns) // * 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> // 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 // 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 // :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 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 m;
let afterSeq; let afterSeq;
let wantMore; let wantMore;
@ -184,7 +184,7 @@ module.exports = function ansiPrep(input, options, cb) {
splitAt = m.index; splitAt = m.index;
wantMore = false; // can't eat up any more wantMore = false; // can't eat up any more
} }
break; // seq's beyond this point are >= MAX_CHARS break; // seq's beyond this point are >= MAX_CHARS
} }
} }
@ -203,7 +203,7 @@ module.exports = function ansiPrep(input, options, cb) {
exportOutput += `${part}\r\n`; exportOutput += `${part}\r\n`;
if(fullLine.length > 0) { // more to go for this line? if(fullLine.length > 0) { // more to go for this line?
exportOutput += `${ANSI.up()}${ANSI.right(renderStart)}`; exportOutput += `${ANSI.up()}${ANSI.right(renderStart)}`;
} else { } else {
exportOutput += ANSI.up(); exportOutput += ANSI.up();
} }

View File

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

View File

@ -23,7 +23,7 @@ class Archiver {
} }
ok() { ok() {
return this.canCompress() && this.canDecompress(); return this.canCompress() && this.canDecompress();
} }
can(what) { can(what) {
@ -41,7 +41,7 @@ class Archiver {
} }
module.exports = class ArchiveUtil { module.exports = class ArchiveUtil {
constructor() { constructor() {
this.archivers = {}; this.archivers = {};
this.longestSignature = 0; this.longestSignature = 0;
@ -93,7 +93,7 @@ module.exports = class ArchiveUtil {
getArchiver(mimeTypeOrExtension) { getArchiver(mimeTypeOrExtension) {
mimeTypeOrExtension = resolveMimeType(mimeTypeOrExtension); mimeTypeOrExtension = resolveMimeType(mimeTypeOrExtension);
if(!mimeTypeOrExtension) { // lookup returns false on failure if(!mimeTypeOrExtension) { // lookup returns false on failure
return; return;
} }
@ -103,21 +103,23 @@ module.exports = class ArchiveUtil {
return _.get( Config, [ 'archives', 'archivers', archiveHandler ] ); return _.get( Config, [ 'archives', 'archivers', archiveHandler ] );
} }
} }
haveArchiver(archType) { haveArchiver(archType) {
return this.getArchiver(archType) ? true : false; return this.getArchiver(archType) ? true : false;
} }
detectTypeWithBuf(buf, cb) { // :TODO: implement me:
// :TODO: implement me! /*
detectTypeWithBuf(buf, cb) {
} }
*/
detectType(path, cb) { detectType(path, cb) {
fs.open(path, 'r', (err, fd) => { fs.open(path, 'r', (err, fd) => {
if(err) { if(err) {
return cb(err); return cb(err);
} }
const buf = new Buffer(this.longestSignature); const buf = new Buffer(this.longestSignature);
fs.read(fd, buf, 0, buf.length, 0, (err, bytesRead) => { fs.read(fd, buf, 0, buf.length, 0, (err, bytesRead) => {
if(err) { if(err) {
@ -140,7 +142,7 @@ module.exports = class ArchiveUtil {
}); });
return cb(archFormat ? null : Errors.General('Unknown type'), archFormat); return cb(archFormat ? null : Errors.General('Unknown type'), archFormat);
}); });
}); });
} }
@ -153,15 +155,15 @@ module.exports = class ArchiveUtil {
err = Errors.ExternalProcess(`${action} failed: ${d.trim()}`); err = Errors.ExternalProcess(`${action} failed: ${d.trim()}`);
} }
}); });
proc.once('exit', exitCode => { proc.once('exit', exitCode => {
return cb(exitCode ? Errors.ExternalProcess(`${action} failed with exit code: ${exitCode}`) : err); return cb(exitCode ? Errors.ExternalProcess(`${action} failed with exit code: ${exitCode}`) : err);
}); });
} }
compressTo(archType, archivePath, files, cb) { compressTo(archType, archivePath, files, cb) {
const archiver = this.getArchiver(archType); const archiver = this.getArchiver(archType);
if(!archiver) { if(!archiver) {
return cb(Errors.Invalid(`Unknown archive type: ${archType}`)); return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
} }
@ -189,13 +191,13 @@ module.exports = class ArchiveUtil {
if(!cb && _.isFunction(fileList)) { if(!cb && _.isFunction(fileList)) {
cb = fileList; cb = fileList;
fileList = []; fileList = [];
haveFileList = false; haveFileList = false;
} else { } else {
haveFileList = true; haveFileList = true;
} }
const archiver = this.getArchiver(archType); const archiver = this.getArchiver(archType);
if(!archiver) { if(!archiver) {
return cb(Errors.Invalid(`Unknown archive type: ${archType}`)); return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
} }
@ -211,7 +213,7 @@ module.exports = class ArchiveUtil {
const args = archiver[action].args.map( arg => { const args = archiver[action].args.map( arg => {
return '{fileList}' === arg ? arg : stringFormat(arg, fmtObj); return '{fileList}' === arg ? arg : stringFormat(arg, fmtObj);
}); });
const fileListPos = args.indexOf('{fileList}'); const fileListPos = args.indexOf('{fileList}');
if(fileListPos > -1) { if(fileListPos > -1) {
// replace {fileList} with 0:n sep file list arguments // replace {fileList} with 0:n sep file list arguments
@ -230,9 +232,9 @@ module.exports = class ArchiveUtil {
listEntries(archivePath, archType, cb) { listEntries(archivePath, archType, cb) {
const archiver = this.getArchiver(archType); const archiver = this.getArchiver(archType);
if(!archiver) { if(!archiver) {
return cb(Errors.Invalid(`Unknown archive type: ${archType}`)); return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
} }
const fmtObj = { const fmtObj = {
@ -240,7 +242,7 @@ module.exports = class ArchiveUtil {
}; };
const args = archiver.list.args.map( arg => stringFormat(arg, fmtObj) ); const args = archiver.list.args.map( arg => stringFormat(arg, fmtObj) );
let proc; let proc;
try { try {
proc = pty.spawn(archiver.list.cmd, args, this.getPtyOpts()); proc = pty.spawn(archiver.list.cmd, args, this.getPtyOpts());
@ -251,7 +253,7 @@ module.exports = class ArchiveUtil {
let output = ''; let output = '';
proc.on('data', data => { proc.on('data', data => {
// :TODO: hack for: execvp(3) failed.: No such file or directory // :TODO: hack for: execvp(3) failed.: No such file or directory
output += data; output += data;
}); });
@ -273,16 +275,16 @@ module.exports = class ArchiveUtil {
} }
return cb(null, entries); return cb(null, entries);
}); });
} }
getPtyOpts() { getPtyOpts() {
return { return {
// :TODO: cwd // :TODO: cwd
name : 'enigma-archiver', name : 'enigma-archiver',
cols : 80, cols : 80,
rows : 24, 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 }, '.pcb' : { name : 'PCBoard', defaultEncoding : 'cp437', eof : 0x1a },
'.bbs' : { name : 'Wildcat', 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 }, '.txt' : { name : 'Amiga Text', defaultEncoding : 'cp437', eof : 0x1a },
// :TODO: extentions for wwiv, renegade, celerity, syncronet, ... // :TODO: extentions for wwiv, renegade, celerity, syncronet, ...
// :TODO: extension for atari // :TODO: extension for atari
@ -93,7 +93,7 @@ function getArtFromPath(path, options, cb) {
} }
return result; return result;
} }
if(options.readSauce === true) { if(options.readSauce === true) {
sauce.readSAUCE(data, (err, sauce) => { sauce.readSAUCE(data, (err, sauce) => {
@ -164,7 +164,7 @@ function getArt(name, options, cb) {
const bn = paths.basename(file, fext).toLowerCase(); const bn = paths.basename(file, fext).toLowerCase();
if(options.random) { if(options.random) {
const suppliedBn = paths.basename(name, fext).toLowerCase(); const suppliedBn = paths.basename(name, fext).toLowerCase();
// //
// Random selection enabled. We'll allow for // Random selection enabled. We'll allow for
// basename1.ext, basename2.ext, ... // basename1.ext, basename2.ext, ...
@ -208,7 +208,7 @@ function getArt(name, options, cb) {
return getArtFromPath(readPath, options, cb); return getArtFromPath(readPath, options, cb);
} }
return cb(new Error(`No matching art for supplied criteria: ${name}`)); 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); return cb(null, mciMap, extraInfo);
} }
if(!options.disableMciCache) { if(!options.disableMciCache) {
artHash = xxhash.hash(new Buffer(art), 0xCAFEBABE); artHash = xxhash.hash(new Buffer(art), 0xCAFEBABE);
// see if we have a mciMap cached for this art // see if we have a mciMap cached for this art
@ -307,7 +307,7 @@ function display(client, art, options, cb) {
if(mciCprQueue.length > 0) { if(mciCprQueue.length > 0) {
mciMap[mciCprQueue.shift()].position = pos; mciMap[mciCprQueue.shift()].position = pos;
if(parseComplete && 0 === mciCprQueue.length) { if(parseComplete && 0 === mciCprQueue.length) {
return completed(); 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('control', control => client.term.rawWrite(control) );
ansiParser.on('complete', () => { ansiParser.on('complete', () => {
@ -353,7 +353,7 @@ function display(client, art, options, cb) {
if(0 === mciCprQueue.length) { if(0 === mciCprQueue.length) {
return completed(); return completed();
} }
}); });
let initSeq = ''; let initSeq = '';

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -68,14 +68,14 @@ function enigmaToAnsi(s, client) {
attr = ansi.sgr(['normal', val - 8, 'bold']); 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; lastIndex = re.lastIndex;
} }
result = (0 === result.length ? s : result + s.substr(lastIndex)); result = (0 === result.length ? s : result + s.substr(lastIndex));
return result; return result;
} }
@ -145,7 +145,7 @@ function renegadeToAnsi(s, client) {
} }
// convert to number // convert to number
val = parseInt(val, 10); val = parseInt(val, 10);
if(isNaN(val)) { if(isNaN(val)) {
val = getPredefinedMCIValue(client, m[1]) || ('|' + m[1]); // value itself or literal val = getPredefinedMCIValue(client, m[1]) || ('|' + m[1]); // value itself or literal
} }
@ -160,7 +160,7 @@ function renegadeToAnsi(s, client) {
lastIndex = re.lastIndex; 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 // * http://wiki.synchro.net/custom:colors
// //
function controlCodesToAnsi(s, client) { 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 m;
let result = ''; 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.host = this.config.host || 'bbs.combatnet.us';
this.config.rloginPort = this.config.rloginPort || 4513; this.config.rloginPort = this.config.rloginPort || 4513;
} }
initSequence() { initSequence() {
const self = this; const self = this;
async.series( async.series(
[ [
function validateConfig(callback) { function validateConfig(callback) {
@ -45,59 +45,59 @@ exports.getModule = class CombatNetModule extends MenuModule {
self.client.term.write('Connecting to CombatNet, please wait...\n'); self.client.term.write('Connecting to CombatNet, please wait...\n');
const restorePipeToNormal = function() { const restorePipeToNormal = function() {
self.client.term.output.removeListener('data', sendToRloginBuffer); self.client.term.output.removeListener('data', sendToRloginBuffer);
}; };
const rlogin = new RLogin( const rlogin = new RLogin(
{ 'clientUsername' : self.config.password, { 'clientUsername' : self.config.password,
'serverUsername' : `${self.config.bbsTag}${self.client.user.username}`, 'serverUsername' : `${self.config.bbsTag}${self.client.user.username}`,
'host' : self.config.host, 'host' : self.config.host,
'port' : self.config.rloginPort, 'port' : self.config.rloginPort,
'terminalType' : self.client.term.termClient, 'terminalType' : self.client.term.termClient,
'terminalSpeed' : 57600 'terminalSpeed' : 57600
} }
); );
// If there was an error ... // If there was an error ...
rlogin.on('error', err => { rlogin.on('error', err => {
self.client.log.info(`CombatNet rlogin client error: ${err.message}`); self.client.log.info(`CombatNet rlogin client error: ${err.message}`);
restorePipeToNormal(); restorePipeToNormal();
callback(err); return callback(err);
}); });
// If we've been disconnected ... // If we've been disconnected ...
rlogin.on('disconnect', () => { rlogin.on('disconnect', () => {
self.client.log.info(`Disconnected from CombatNet`); self.client.log.info('Disconnected from CombatNet');
restorePipeToNormal(); restorePipeToNormal();
callback(null); return callback(null);
}); });
function sendToRloginBuffer(buffer) { function sendToRloginBuffer(buffer) {
rlogin.send(buffer); rlogin.send(buffer);
}; }
rlogin.on("connect", rlogin.on('connect',
/* The 'connect' event handler will be supplied with one argument, /* The 'connect' event handler will be supplied with one argument,
a boolean indicating whether or not the connection was established. */ a boolean indicating whether or not the connection was established. */
function(state) { function(state) {
if(state) { if(state) {
self.client.log.info('Connected to CombatNet'); self.client.log.info('Connected to CombatNet');
self.client.term.output.on('data', sendToRloginBuffer); self.client.term.output.on('data', sendToRloginBuffer);
} else { } else {
return callback(new Error('Failed to establish establish CombatNet connection')); return callback(new Error('Failed to establish establish CombatNet connection'));
} }
} }
); );
// If data (a Buffer) has been received from the server ... // If data (a Buffer) has been received from the server ...
rlogin.on("data", (data) => { rlogin.on('data', (data) => {
self.client.term.rawWrite(data); self.client.term.rawWrite(data);
}); });
// connect... // connect...
rlogin.connect(); rlogin.connect();
// note: no explicit callback() until we're finished! // note: no explicit callback() until we're finished!
} }
@ -106,10 +106,10 @@ exports.getModule = class CombatNetModule extends MenuModule {
if(err) { if(err) {
self.client.log.warn( { error : err.message }, 'CombatNet error'); self.client.log.warn( { error : err.message }, 'CombatNet error');
} }
// if the client is still here, go to previous // if the client is still here, go to previous
self.prevMenu(); self.prevMenu();
} }
); );
} }
}; };

View File

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

View File

@ -653,12 +653,12 @@ function getDefaultConfig() {
// FILE_ID.DIZ - https://en.wikipedia.org/wiki/FILE_ID.DIZ // 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. // Some groups include a FILE_ID.ANS. We try to use that over FILE_ID.DIZ if available.
desc : [ 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 // common README filename - https://en.wikipedia.org/wiki/README
descLong : [ 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) { ConfigCache.prototype.getConfigWithOptions = function(options, cb) {
assert(_.isString(options.filePath)); assert(_.isString(options.filePath));
// var self = this; // var self = this;
var isCached = (options.filePath in this.cache); var isCached = (options.filePath in this.cache);
if(options.forceReCache || !isCached) { if(options.forceReCache || !isCached) {

View File

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

View File

@ -10,7 +10,7 @@ exports.CRC32 = class CRC32 {
} }
update(input) { 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); 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 ]; this.crc = (this.crc >>> 8) ^ CRC32_TABLE[ (this.crc ^ input[i++] ) & 0xff ];
} }
} }
finalize() { finalize() {
return (this.crc ^ (-1)) >>> 0; 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) // 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 // We expect that moduleInfo defines packageName which will be the base of the modules
// filename. An optional suffix may be supplied as well. // 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(_.isObject(moduleInfo));
assert(_.isString(moduleInfo.packageName), 'moduleInfo must define "packageName"!'); assert(_.isString(moduleInfo.packageName), 'moduleInfo must define "packageName"!');
let full = moduleInfo.packageName; let full = moduleInfo.packageName;
if(suffix) { if(suffix) {
full += `.${suffix}`; full += `.${suffix}`;
@ -198,7 +198,7 @@ const DB_INIT_TABLE = {
DELETE FROM message_fts WHERE docid=old.rowid; DELETE FROM message_fts WHERE docid=old.rowid;
END;` END;`
); );
dbs.message.run( dbs.message.run(
`CREATE TRIGGER IF NOT EXISTS message_before_delete BEFORE DELETE ON message BEGIN `CREATE TRIGGER IF NOT EXISTS message_before_delete BEFORE DELETE ON message BEGIN
DELETE FROM message_fts WHERE docid=old.rowid; DELETE FROM message_fts WHERE docid=old.rowid;
@ -256,14 +256,14 @@ const DB_INIT_TABLE = {
UNIQUE(user_id, area_tag) UNIQUE(user_id, area_tag)
);` );`
); );
dbs.message.run( dbs.message.run(
`CREATE TABLE IF NOT EXISTS message_area_last_scan ( `CREATE TABLE IF NOT EXISTS message_area_last_scan (
scan_toss VARCHAR NOT NULL, scan_toss VARCHAR NOT NULL,
area_tag VARCHAR NOT NULL, area_tag VARCHAR NOT NULL,
message_id INTEGER NOT NULL, message_id INTEGER NOT NULL,
UNIQUE(scan_toss, area_tag) UNIQUE(scan_toss, area_tag)
);` );`
); );
return cb(null); return cb(null);

View File

@ -20,7 +20,7 @@ function Door(client, exeInfo) {
this.exeInfo = exeInfo; this.exeInfo = exeInfo;
this.exeInfo.encoding = this.exeInfo.encoding || 'cp437'; this.exeInfo.encoding = this.exeInfo.encoding || 'cp437';
this.exeInfo.encoding = this.exeInfo.encoding.toLowerCase(); this.exeInfo.encoding = this.exeInfo.encoding.toLowerCase();
let restored = false; let restored = false;
// //
// Members of exeInfo: // Members of exeInfo:
@ -52,7 +52,7 @@ function Door(client, exeInfo) {
}; };
this.prepareSocketIoServer = function(cb) { this.prepareSocketIoServer = function(cb) {
if('socket' === self.exeInfo.io) { if('socket' === self.exeInfo.io) {
const sockServer = createServer(conn => { const sockServer = createServer(conn => {
sockServer.getConnections( (err, count) => { sockServer.getConnections( (err, count) => {
@ -60,11 +60,11 @@ function Door(client, exeInfo) {
// We expect only one connection from our DOOR/emulator/etc. // We expect only one connection from our DOOR/emulator/etc.
if(!err && count <= 1) { if(!err && count <= 1) {
self.client.term.output.pipe(conn); self.client.term.output.pipe(conn);
conn.on('data', self.doorDataHandler); conn.on('data', self.doorDataHandler);
conn.once('end', () => { conn.once('end', () => {
return self.restoreIo(conn); return self.restoreIo(conn);
}); });
conn.once('error', err => { conn.once('error', err => {
@ -117,7 +117,7 @@ Door.prototype.run = function() {
rows : self.client.term.termHeight, rows : self.client.term.termHeight,
// :TODO: cwd // :TODO: cwd
env : self.exeInfo.env, env : self.exeInfo.env,
}); });
if('stdio' === self.exeInfo.io) { if('stdio' === self.exeInfo.io) {
self.client.log.debug('Using stdio for door I/O'); 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 = options.menuConfig.config;
this.config.host = this.config.host || 'dp.throwbackbbs.com'; this.config.host = this.config.host || 'dp.throwbackbbs.com';
this.config.sshPort = this.config.sshPort || 2022; this.config.sshPort = this.config.sshPort || 2022;
this.config.rloginPort = this.config.rloginPort || 513; this.config.rloginPort = this.config.rloginPort || 513;
} }
initSequence() { initSequence() {
let clientTerminated; let clientTerminated;
const self = this; const self = this;
async.series( async.series(
[ [
function validateConfig(callback) { function validateConfig(callback) {
@ -48,26 +48,26 @@ exports.getModule = class DoorPartyModule extends MenuModule {
function establishSecureConnection(callback) { function establishSecureConnection(callback) {
self.client.term.write(resetScreen()); self.client.term.write(resetScreen());
self.client.term.write('Connecting to DoorParty, please wait...\n'); self.client.term.write('Connecting to DoorParty, please wait...\n');
const sshClient = new SSHClient(); const sshClient = new SSHClient();
let pipeRestored = false; let pipeRestored = false;
let pipedStream; let pipedStream;
const restorePipe = function() { const restorePipe = function() {
if(pipedStream && !pipeRestored && !clientTerminated) { if(pipedStream && !pipeRestored && !clientTerminated) {
self.client.term.output.unpipe(pipedStream); self.client.term.output.unpipe(pipedStream);
self.client.term.output.resume(); self.client.term.output.resume();
} }
}; };
sshClient.on('ready', () => { sshClient.on('ready', () => {
// track client termination so we can clean up early // track client termination so we can clean up early
self.client.once('end', () => { self.client.once('end', () => {
self.client.log.info('Connection ended. Terminating DoorParty connection'); self.client.log.info('Connection ended. Terminating DoorParty connection');
clientTerminated = true; clientTerminated = true;
sshClient.end(); sshClient.end();
}); });
// establish tunnel for rlogin // establish tunnel for rlogin
sshClient.forwardOut('127.0.0.1', self.config.sshPort, self.config.host, self.config.rloginPort, (err, stream) => { sshClient.forwardOut('127.0.0.1', self.config.sshPort, self.config.host, self.config.rloginPort, (err, stream) => {
if(err) { 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. // DoorParty wants the "server username" portion to be in the format of [BBS_TAG]USERNAME, e.g.
// [XA]nuskooler // [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); stream.write(rlogin);
pipedStream = stream; // :TODO: this is hacky... pipedStream = stream; // :TODO: this is hacky...
self.client.term.output.pipe(stream); self.client.term.output.pipe(stream);
stream.on('data', d => { stream.on('data', d => {
// :TODO: we should just pipe this... // :TODO: we should just pipe this...
self.client.term.rawWrite(d); self.client.term.rawWrite(d);
}); });
stream.on('close', () => { stream.on('close', () => {
restorePipe(); restorePipe();
sshClient.end(); sshClient.end();
@ -100,32 +100,32 @@ exports.getModule = class DoorPartyModule extends MenuModule {
sshClient.on('error', err => { sshClient.on('error', err => {
self.client.log.info(`DoorParty SSH client error: ${err.message}`); self.client.log.info(`DoorParty SSH client error: ${err.message}`);
}); });
sshClient.on('close', () => { sshClient.on('close', () => {
restorePipe(); restorePipe();
callback(null); callback(null);
}); });
sshClient.connect( { sshClient.connect( {
host : self.config.host, host : self.config.host,
port : self.config.sshPort, port : self.config.sshPort,
username : self.config.username, username : self.config.username,
password : self.config.password, password : self.config.password,
}); });
// note: no explicit callback() until we're finished! // note: no explicit callback() until we're finished!
} }
], ],
err => { err => {
if(err) { if(err) {
self.client.log.warn( { error : err.message }, 'DoorParty error'); self.client.log.warn( { error : err.message }, 'DoorParty error');
} }
// if the client is stil here, go to previous // if the client is stil here, go to previous
if(!clientTerminated) { if(!clientTerminated) {
self.prevMenu(); self.prevMenu();
} }
} }
); );
} }
}; };

View File

@ -59,14 +59,14 @@ module.exports = class DownloadQueue {
} }
toProperty() { return JSON.stringify(this.client.user.downloadQueue); } toProperty() { return JSON.stringify(this.client.user.downloadQueue); }
loadFromProperty(prop) { loadFromProperty(prop) {
try { try {
this.client.user.downloadQueue = JSON.parse(prop); this.client.user.downloadQueue = JSON.parse(prop);
} catch(e) { } catch(e) {
this.client.user.downloadQueue = []; 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.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true);
options.cursorStyle = miscUtil.valueWithDefault(options.cursorStyle, 'steady block'); options.cursorStyle = miscUtil.valueWithDefault(options.cursorStyle, 'steady block');
options.resizable = false; options.resizable = false;
TextView.call(this, options); TextView.call(this, options);
this.cursorPos = { row : 0, col : 0 }; 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); return EditTextView.super_.prototype.onKeyPress.call(this, ch, key);
} else if(this.isKeyMapped('clearLine', key.name)) { } else if(this.isKeyMapped('clearLine', key.name)) {
this.text = ''; this.text = '';

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -32,13 +32,13 @@ const MciViewIds = {
queueManager : { queueManager : {
queue : 1, queue : 1,
navMenu : 2, navMenu : 2,
customRangeStart : 10, customRangeStart : 10,
} }
}; };
exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule { exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
constructor(options) { constructor(options) {
super(options); super(options);
@ -58,7 +58,7 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
}, },
clearQueue : (formData, extraArgs, cb) => { clearQueue : (formData, extraArgs, cb) => {
this.dlQueue.clear(); this.dlQueue.clear();
// :TODO: broken: does not redraw menu properly - needs fixed! // :TODO: broken: does not redraw menu properly - needs fixed!
return this.removeItemsFromDownloadQueueView('all', cb); return this.removeItemsFromDownloadQueueView('all', cb);
}, },
@ -109,7 +109,7 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
displayFileInfoForFileEntry(fileEntry) { displayFileInfoForFileEntry(fileEntry) {
this.updateCustomViewTextsWithFilter( this.updateCustomViewTextsWithFilter(
'queueManager', 'queueManager',
MciViewIds.queueManager.customRangeStart, fileEntry, MciViewIds.queueManager.customRangeStart, fileEntry,
{ filter : [ '{webDlLink}', '{webDlExpire}', '{fileName}' ] } // :TODO: Others.... { 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'); const expireTime = moment().add(Config.fileBase.web.expireMinutes, 'minutes');
FileAreaWeb.createAndServeTempBatchDownload( FileAreaWeb.createAndServeTempBatchDownload(
this.client, this.client,
this.dlQueue.items, this.dlQueue.items,
{ {
expireTime : expireTime expireTime : expireTime
@ -162,7 +162,7 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
this.updateCustomViewTextsWithFilter( this.updateCustomViewTextsWithFilter(
'queueManager', 'queueManager',
MciViewIds.queueManager.customRangeStart, MciViewIds.queueManager.customRangeStart,
formatObj, formatObj,
{ filter : Object.keys(formatObj).map(k => '{' + k + '}' ) } { filter : Object.keys(formatObj).map(k => '{' + k + '}' ) }
); );
@ -187,13 +187,13 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
FileAreaWeb.getExistingTempDownloadServeItem(self.client, fileEntry, (err, serveItem) => { FileAreaWeb.getExistingTempDownloadServeItem(self.client, fileEntry, (err, serveItem) => {
if(err) { if(err) {
if(ErrNotEnabled === err.reasonCode) { 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'); const expireTime = moment().add(Config.fileBase.web.expireMinutes, 'minutes');
FileAreaWeb.createAndServeTempDownload( FileAreaWeb.createAndServeTempDownload(
self.client, self.client,
fileEntry, fileEntry,
{ expireTime : expireTime }, { expireTime : expireTime },
(err, url) => { (err, url) => {
@ -202,13 +202,13 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
} }
fileEntry.webDlLinkRaw = url; fileEntry.webDlLinkRaw = url;
fileEntry.webDlLink = ansi.vtxHyperlink(self.client, url) + url; fileEntry.webDlLink = ansi.vtxHyperlink(self.client, url) + url;
fileEntry.webDlExpire = expireTime.format(webDlExpireTimeFormat); fileEntry.webDlExpire = expireTime.format(webDlExpireTimeFormat);
return nextFileEntry(null); return nextFileEntry(null);
} }
); );
} else { } else {
fileEntry.webDlLinkRaw = serveItem.url; fileEntry.webDlLinkRaw = serveItem.url;
fileEntry.webDlLink = ansi.vtxHyperlink(self.client, serveItem.url) + serveItem.url; fileEntry.webDlLink = ansi.vtxHyperlink(self.client, serveItem.url) + serveItem.url;
fileEntry.webDlExpire = moment(serveItem.expireTimestamp).format(webDlExpireTimeFormat); fileEntry.webDlExpire = moment(serveItem.expireTimestamp).format(webDlExpireTimeFormat);
@ -272,10 +272,10 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
return vc.loadFromMenuConfig(loadOpts, callback); return vc.loadFromMenuConfig(loadOpts, callback);
} }
self.viewControllers[name].setFocus(true); self.viewControllers[name].setFocus(true);
return callback(null); return callback(null);
}, },
], ],
err => { 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 crypto = require('crypto');
const moment = require('moment'); const moment = require('moment');
const FILE_TABLE_MEMBERS = [ const FILE_TABLE_MEMBERS = [
'file_id', 'area_tag', 'file_sha256', 'file_name', 'storage_tag', 'file_id', 'area_tag', 'file_sha256', 'file_name', 'storage_tag',
'desc', 'desc_long', 'upload_timestamp' 'desc', 'desc_long', 'upload_timestamp'
]; ];
@ -47,7 +47,7 @@ module.exports = class FileEntry {
// values we always want // values we always want
dl_count : 0, dl_count : 0,
}; };
this.hashTags = options.hashTags || new Set(); this.hashTags = options.hashTags || new Set();
this.fileName = options.fileName; this.fileName = options.fileName;
this.storageTag = options.storageTag; this.storageTag = options.storageTag;
@ -173,7 +173,7 @@ module.exports = class FileEntry {
async.each(Object.keys(self.meta), (n, next) => { async.each(Object.keys(self.meta), (n, next) => {
const v = self.meta[n]; const v = self.meta[n];
return FileEntry.persistMetaValue(self.fileId, n, v, trans, next); return FileEntry.persistMetaValue(self.fileId, n, v, trans, next);
}, },
err => { err => {
return callback(err, trans); return callback(err, trans);
}); });
@ -185,7 +185,7 @@ module.exports = class FileEntry {
}, },
err => { err => {
return callback(err, trans); return callback(err, trans);
}); });
} }
], ],
(err, trans) => { (err, trans) => {
@ -203,10 +203,10 @@ module.exports = class FileEntry {
static getAreaStorageDirectoryByTag(storageTag) { static getAreaStorageDirectoryByTag(storageTag) {
const storageLocation = (storageTag && Config.fileBase.storageTags[storageTag]); const storageLocation = (storageTag && Config.fileBase.storageTags[storageTag]);
// absolute paths as-is // absolute paths as-is
if(storageLocation && '/' === storageLocation.charAt(0)) { if(storageLocation && '/' === storageLocation.charAt(0)) {
return storageLocation; return storageLocation;
} }
// relative to |areaStoragePrefix| // relative to |areaStoragePrefix|
@ -283,7 +283,7 @@ module.exports = class FileEntry {
transOrDb.serialize( () => { transOrDb.serialize( () => {
transOrDb.run( transOrDb.run(
`INSERT OR IGNORE INTO hash_tag (hash_tag) `INSERT OR IGNORE INTO hash_tag (hash_tag)
VALUES (?);`, VALUES (?);`,
[ hashTag ] [ hashTag ]
); );
@ -321,7 +321,7 @@ module.exports = class FileEntry {
err => { err => {
return cb(err); return cb(err);
} }
); );
} }
loadRating(cb) { loadRating(cb) {
@ -352,7 +352,7 @@ module.exports = class FileEntry {
} }
static get WellKnownMetaValues() { static get WellKnownMetaValues() {
return Object.keys(FILE_WELL_KNOWN_META); return Object.keys(FILE_WELL_KNOWN_META);
} }
static findFileBySha(sha, cb) { static findFileBySha(sha, cb) {
@ -469,7 +469,7 @@ module.exports = class FileEntry {
sqlOrderBy = `ORDER BY avg_rating ${sqlOrderDir}`; sqlOrderBy = `ORDER BY avg_rating ${sqlOrderDir}`;
} else { } else {
sql = sql =
`SELECT DISTINCT f.file_id, f.${filter.sort} `SELECT DISTINCT f.file_id, f.${filter.sort}
FROM file f`; FROM file f`;
@ -531,7 +531,7 @@ module.exports = class FileEntry {
)` )`
); );
} }
if(filter.tags && filter.tags.length > 0) { if(filter.tags && filter.tags.length > 0) {
// build list of quoted tags; filter.tags comes in as a space and/or comma separated values // 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(','); 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 srcPath = srcFileEntry.filePath;
const dstDir = FileEntry.getAreaStorageDirectoryByTag(destStorageTag); const dstDir = FileEntry.getAreaStorageDirectoryByTag(destStorageTag);
if(!dstDir) { if(!dstDir) {
return cb(Errors.Invalid('Invalid storage tag')); return cb(Errors.Invalid('Invalid storage tag'));
} }

View File

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

View File

@ -66,11 +66,11 @@ function moveOrCopyFileWithCollisionHandling(src, dst, operation, cb) {
(err, finalPath) => { (err, finalPath) => {
return 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. // in the case of collisions.
// //
function moveFileWithCollisionHandling(src, dst, cb) { function moveFileWithCollisionHandling(src, dst, cb) {

View File

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

View File

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

View File

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

View File

@ -56,7 +56,7 @@ class PacketHeader {
this.capWordValidate = ((this.capWord & 0xff) << 8) | ((this.capWord >> 8) & 0xff); // swap this.capWordValidate = ((this.capWord & 0xff) << 8) | ((this.capWord >> 8) & 0xff); // swap
this.prodCodeHi = 0xfe; // see above this.prodCodeHi = 0xfe; // see above
this.prodRevHi = 0; this.prodRevHi = 0;
} }
get origAddress() { get origAddress() {
@ -84,9 +84,9 @@ class PacketHeader {
// See FSC-48 // See FSC-48
// :TODO: disabled for now until we have separate packet writers for 2, 2+, 2+48, and 2.2 // :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.auxNet = address.origNet;
this.origNet = -1; this.origNet = -1;
} else { } else {
this.origNet = address.net; this.origNet = address.net;
this.auxNet = 0; this.auxNet = 0;
@ -158,16 +158,16 @@ exports.PacketHeader = PacketHeader;
// //
// * Type 2 FTS-0001 @ http://ftsc.org/docs/fts-0001.016 (Obsolete) // * 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.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 // and http://ftsc.org/docs/fsc-0048.002
// //
// Additional resources: // Additional resources:
// * Writeup on differences between type 2, 2.2, and 2+: // * Writeup on differences between type 2, 2.2, and 2+:
// http://walon.org/pub/fidonet/FTSC-nodelists-etc./pkt-types.txt // http://walon.org/pub/fidonet/FTSC-nodelists-etc./pkt-types.txt
// //
function Packet(options) { function Packet(options) {
var self = this; var self = this;
this.options = options || {}; this.options = options || {};
this.parsePacketHeader = function(packetBuffer, cb) { this.parsePacketHeader = function(packetBuffer, cb) {
@ -240,11 +240,11 @@ function Packet(options) {
// //
// See heuristics described in FSC-0048, "Receiving Type-2+ bundles" // See heuristics described in FSC-0048, "Receiving Type-2+ bundles"
// //
const capWordValidateSwapped = const capWordValidateSwapped =
((packetHeader.capWordValidate & 0xff) << 8) | ((packetHeader.capWordValidate & 0xff) << 8) |
((packetHeader.capWordValidate >> 8) & 0xff); ((packetHeader.capWordValidate >> 8) & 0xff);
if(capWordValidateSwapped === packetHeader.capWord && if(capWordValidateSwapped === packetHeader.capWord &&
0 != packetHeader.capWord && 0 != packetHeader.capWord &&
packetHeader.capWord & 0x0001) packetHeader.capWord & 0x0001)
{ {
@ -260,7 +260,7 @@ function Packet(options) {
// :TODO: should fill bytes be 0? // :TODO: should fill bytes be 0?
} }
} }
packetHeader.created = moment({ packetHeader.created = moment({
year : packetHeader.year, year : packetHeader.year,
month : packetHeader.month - 1, // moment uses 0 indexed months month : packetHeader.month - 1, // moment uses 0 indexed months
@ -269,36 +269,36 @@ function Packet(options) {
minute : packetHeader.minute, minute : packetHeader.minute,
second : packetHeader.second second : packetHeader.second
}); });
let ph = new PacketHeader(); let ph = new PacketHeader();
_.assign(ph, packetHeader); _.assign(ph, packetHeader);
cb(null, ph); cb(null, ph);
}); });
}; };
this.getPacketHeaderBuffer = function(packetHeader) { this.getPacketHeaderBuffer = function(packetHeader) {
let buffer = new Buffer(FTN_PACKET_HEADER_SIZE); let buffer = new Buffer(FTN_PACKET_HEADER_SIZE);
buffer.writeUInt16LE(packetHeader.origNode, 0); buffer.writeUInt16LE(packetHeader.origNode, 0);
buffer.writeUInt16LE(packetHeader.destNode, 2); buffer.writeUInt16LE(packetHeader.destNode, 2);
buffer.writeUInt16LE(packetHeader.year, 4); buffer.writeUInt16LE(packetHeader.year, 4);
buffer.writeUInt16LE(packetHeader.month, 6); buffer.writeUInt16LE(packetHeader.month, 6);
buffer.writeUInt16LE(packetHeader.day, 8); buffer.writeUInt16LE(packetHeader.day, 8);
buffer.writeUInt16LE(packetHeader.hour, 10); buffer.writeUInt16LE(packetHeader.hour, 10);
buffer.writeUInt16LE(packetHeader.minute, 12); buffer.writeUInt16LE(packetHeader.minute, 12);
buffer.writeUInt16LE(packetHeader.second, 14); buffer.writeUInt16LE(packetHeader.second, 14);
buffer.writeUInt16LE(packetHeader.baud, 16); buffer.writeUInt16LE(packetHeader.baud, 16);
buffer.writeUInt16LE(FTN_PACKET_HEADER_TYPE, 18); buffer.writeUInt16LE(FTN_PACKET_HEADER_TYPE, 18);
buffer.writeUInt16LE(-1 === packetHeader.origNet ? 0xffff : packetHeader.origNet, 20); buffer.writeUInt16LE(-1 === packetHeader.origNet ? 0xffff : packetHeader.origNet, 20);
buffer.writeUInt16LE(packetHeader.destNet, 22); buffer.writeUInt16LE(packetHeader.destNet, 22);
buffer.writeUInt8(packetHeader.prodCodeLo, 24); buffer.writeUInt8(packetHeader.prodCodeLo, 24);
buffer.writeUInt8(packetHeader.prodRevHi, 25); buffer.writeUInt8(packetHeader.prodRevHi, 25);
const pass = ftn.stringToNullPaddedBuffer(packetHeader.password, 8); const pass = ftn.stringToNullPaddedBuffer(packetHeader.password, 8);
pass.copy(buffer, 26); pass.copy(buffer, 26);
buffer.writeUInt16LE(packetHeader.origZone, 34); buffer.writeUInt16LE(packetHeader.origZone, 34);
buffer.writeUInt16LE(packetHeader.destZone, 36); buffer.writeUInt16LE(packetHeader.destZone, 36);
buffer.writeUInt16LE(packetHeader.auxNet, 38); buffer.writeUInt16LE(packetHeader.auxNet, 38);
@ -311,7 +311,7 @@ function Packet(options) {
buffer.writeUInt16LE(packetHeader.origPoint, 50); buffer.writeUInt16LE(packetHeader.origPoint, 50);
buffer.writeUInt16LE(packetHeader.destPoint, 52); buffer.writeUInt16LE(packetHeader.destPoint, 52);
buffer.writeUInt32LE(packetHeader.prodData, 54); buffer.writeUInt32LE(packetHeader.prodData, 54);
return buffer; return buffer;
}; };
@ -321,22 +321,22 @@ function Packet(options) {
buffer.writeUInt16LE(packetHeader.origNode, 0); buffer.writeUInt16LE(packetHeader.origNode, 0);
buffer.writeUInt16LE(packetHeader.destNode, 2); buffer.writeUInt16LE(packetHeader.destNode, 2);
buffer.writeUInt16LE(packetHeader.year, 4); buffer.writeUInt16LE(packetHeader.year, 4);
buffer.writeUInt16LE(packetHeader.month, 6); buffer.writeUInt16LE(packetHeader.month, 6);
buffer.writeUInt16LE(packetHeader.day, 8); buffer.writeUInt16LE(packetHeader.day, 8);
buffer.writeUInt16LE(packetHeader.hour, 10); buffer.writeUInt16LE(packetHeader.hour, 10);
buffer.writeUInt16LE(packetHeader.minute, 12); buffer.writeUInt16LE(packetHeader.minute, 12);
buffer.writeUInt16LE(packetHeader.second, 14); buffer.writeUInt16LE(packetHeader.second, 14);
buffer.writeUInt16LE(packetHeader.baud, 16); buffer.writeUInt16LE(packetHeader.baud, 16);
buffer.writeUInt16LE(FTN_PACKET_HEADER_TYPE, 18); buffer.writeUInt16LE(FTN_PACKET_HEADER_TYPE, 18);
buffer.writeUInt16LE(-1 === packetHeader.origNet ? 0xffff : packetHeader.origNet, 20); buffer.writeUInt16LE(-1 === packetHeader.origNet ? 0xffff : packetHeader.origNet, 20);
buffer.writeUInt16LE(packetHeader.destNet, 22); buffer.writeUInt16LE(packetHeader.destNet, 22);
buffer.writeUInt8(packetHeader.prodCodeLo, 24); buffer.writeUInt8(packetHeader.prodCodeLo, 24);
buffer.writeUInt8(packetHeader.prodRevHi, 25); buffer.writeUInt8(packetHeader.prodRevHi, 25);
const pass = ftn.stringToNullPaddedBuffer(packetHeader.password, 8); const pass = ftn.stringToNullPaddedBuffer(packetHeader.password, 8);
pass.copy(buffer, 26); pass.copy(buffer, 26);
buffer.writeUInt16LE(packetHeader.origZone, 34); buffer.writeUInt16LE(packetHeader.origZone, 34);
buffer.writeUInt16LE(packetHeader.destZone, 36); buffer.writeUInt16LE(packetHeader.destZone, 36);
buffer.writeUInt16LE(packetHeader.auxNet, 38); buffer.writeUInt16LE(packetHeader.auxNet, 38);
@ -376,9 +376,9 @@ function Packet(options) {
// likely need to re-decode as the specified encoding // likely need to re-decode as the specified encoding
// * SAUCE is binary-ish data, so we need to inspect for it before any // * SAUCE is binary-ish data, so we need to inspect for it before any
// decoding occurs // decoding occurs
// //
let messageBodyData = { let messageBodyData = {
message : [], message : [],
kludgeLines : {}, // KLUDGE:[value1, value2, ...] map kludgeLines : {}, // KLUDGE:[value1, value2, ...] map
seenBy : [], seenBy : [],
}; };
@ -411,7 +411,7 @@ function Packet(options) {
messageBodyData.kludgeLines[key] = value; messageBodyData.kludgeLines[key] = value;
} }
} }
let encoding = 'cp437'; let encoding = 'cp437';
async.series( async.series(
@ -426,12 +426,12 @@ function Packet(options) {
if(!err) { if(!err) {
// we read some SAUCE - don't re-process that portion into the body // 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.slice(sauceHeaderPosition + sauce.SAUCE_SIZE);
// messageBodyBuffer = messageBodyBuffer.slice(0, sauceHeaderPosition); // messageBodyBuffer = messageBodyBuffer.slice(0, sauceHeaderPosition);
messageBodyData.sauce = theSauce; messageBodyData.sauce = theSauce;
} else { } 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 { } else {
callback(null); callback(null);
@ -482,7 +482,7 @@ function Packet(options) {
Log.debug( { encoding : encoding, error : e.toString() }, 'Error decoding. Falling back to ASCII'); Log.debug( { encoding : encoding, error : e.toString() }, 'Error decoding. Falling back to ASCII');
decoded = iconv.decode(messageBodyBuffer, 'ascii'); decoded = iconv.decode(messageBodyBuffer, 'ascii');
} }
const messageLines = strUtil.splitTextAtTerms(decoded.replace(/\xec/g, '')); const messageLines = strUtil.splitTextAtTerms(decoded.replace(/\xec/g, ''));
let endOfMessage = false; let endOfMessage = false;
@ -491,13 +491,13 @@ function Packet(options) {
messageBodyData.message.push(''); messageBodyData.message.push('');
return; return;
} }
if(line.startsWith('AREA:')) { if(line.startsWith('AREA:')) {
messageBodyData.area = line.substring(line.indexOf(':') + 1).trim(); messageBodyData.area = line.substring(line.indexOf(':') + 1).trim();
} else if(line.startsWith('--- ')) { } else if(line.startsWith('--- ')) {
// Tear Lines are tracked allowing for specialized display/etc. // Tear Lines are tracked allowing for specialized display/etc.
messageBodyData.tearLine = line; 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; messageBodyData.originLine = line;
endOfMessage = true; // Anything past origin is not part of the message body endOfMessage = true; // Anything past origin is not part of the message body
} else if(line.startsWith('SEEN-BY:')) { } else if(line.startsWith('SEEN-BY:')) {
@ -523,7 +523,7 @@ function Packet(options) {
} }
); );
}; };
this.parsePacketMessages = function(packetBuffer, iterator, cb) { this.parsePacketMessages = function(packetBuffer, iterator, cb) {
binary.parse(packetBuffer) binary.parse(packetBuffer)
.word16lu('messageType') .word16lu('messageType')
@ -540,22 +540,22 @@ function Packet(options) {
.scan('message', NULL_TERM_BUFFER) .scan('message', NULL_TERM_BUFFER)
.tap(function tapped(msgData) { // no arrow function; want classic this .tap(function tapped(msgData) { // no arrow function; want classic this
if(!msgData.messageType) { if(!msgData.messageType) {
// end marker -- no more messages // end marker -- no more messages
return cb(null); return cb(null);
} }
if(FTN_PACKET_MESSAGE_TYPE != msgData.messageType) { if(FTN_PACKET_MESSAGE_TYPE != msgData.messageType) {
return cb(new Error('Unsupported message type: ' + msgData.messageType)); return cb(new Error('Unsupported message type: ' + msgData.messageType));
} }
const read = const read =
14 + // fixed header size 14 + // fixed header size
msgData.modDateTime.length + 1 + msgData.modDateTime.length + 1 +
msgData.toUserName.length + 1 + msgData.toUserName.length + 1 +
msgData.fromUserName.length + 1 + msgData.fromUserName.length + 1 +
msgData.subject.length + 1 + msgData.subject.length + 1 +
msgData.message.length + 1; msgData.message.length + 1;
// //
// Convert null terminated arrays to strings // Convert null terminated arrays to strings
// //
@ -575,7 +575,7 @@ function Packet(options) {
subject : convMsgData.subject, subject : convMsgData.subject,
modTimestamp : ftn.getDateFromFtnDateTime(convMsgData.modDateTime), modTimestamp : ftn.getDateFromFtnDateTime(convMsgData.modDateTime),
}); });
msg.meta.FtnProperty = {}; msg.meta.FtnProperty = {};
msg.meta.FtnProperty.ftn_orig_node = msgData.ftn_orig_node; msg.meta.FtnProperty.ftn_orig_node = msgData.ftn_orig_node;
msg.meta.FtnProperty.ftn_dest_node = msgData.ftn_dest_node; msg.meta.FtnProperty.ftn_dest_node = msgData.ftn_dest_node;
@ -587,31 +587,31 @@ function Packet(options) {
self.processMessageBody(msgData.message, messageBodyData => { self.processMessageBody(msgData.message, messageBodyData => {
msg.message = messageBodyData.message; msg.message = messageBodyData.message;
msg.meta.FtnKludge = messageBodyData.kludgeLines; msg.meta.FtnKludge = messageBodyData.kludgeLines;
if(messageBodyData.tearLine) { if(messageBodyData.tearLine) {
msg.meta.FtnProperty.ftn_tear_line = messageBodyData.tearLine; msg.meta.FtnProperty.ftn_tear_line = messageBodyData.tearLine;
if(self.options.keepTearAndOrigin) { if(self.options.keepTearAndOrigin) {
msg.message += `\r\n${messageBodyData.tearLine}\r\n`; msg.message += `\r\n${messageBodyData.tearLine}\r\n`;
} }
} }
if(messageBodyData.seenBy.length > 0) { if(messageBodyData.seenBy.length > 0) {
msg.meta.FtnProperty.ftn_seen_by = messageBodyData.seenBy; msg.meta.FtnProperty.ftn_seen_by = messageBodyData.seenBy;
} }
if(messageBodyData.area) { if(messageBodyData.area) {
msg.meta.FtnProperty.ftn_area = messageBodyData.area; msg.meta.FtnProperty.ftn_area = messageBodyData.area;
} }
if(messageBodyData.originLine) { if(messageBodyData.originLine) {
msg.meta.FtnProperty.ftn_origin = messageBodyData.originLine; msg.meta.FtnProperty.ftn_origin = messageBodyData.originLine;
if(self.options.keepTearAndOrigin) { if(self.options.keepTearAndOrigin) {
msg.message += `${messageBodyData.originLine}\r\n`; msg.message += `${messageBodyData.originLine}\r\n`;
} }
} }
// //
// If we have a UTC offset kludge (e.g. TZUTC) then update // If we have a UTC offset kludge (e.g. TZUTC) then update
// modDateTime with it // modDateTime with it
@ -619,7 +619,7 @@ function Packet(options) {
if(_.isString(msg.meta.FtnKludge.TZUTC) && msg.meta.FtnKludge.TZUTC.length > 0) { if(_.isString(msg.meta.FtnKludge.TZUTC) && msg.meta.FtnKludge.TZUTC.length > 0) {
msg.modDateTime = msg.modTimestamp.utcOffset(msg.meta.FtnKludge.TZUTC); msg.modDateTime = msg.modTimestamp.utcOffset(msg.meta.FtnKludge.TZUTC);
} }
const nextBuf = packetBuffer.slice(read); const nextBuf = packetBuffer.slice(read);
if(nextBuf.length > 0) { if(nextBuf.length > 0) {
let next = function(e) { let next = function(e) {
@ -629,12 +629,12 @@ function Packet(options) {
self.parsePacketMessages(nextBuf, iterator, cb); self.parsePacketMessages(nextBuf, iterator, cb);
} }
}; };
iterator('message', msg, next); iterator('message', msg, next);
} else { } else {
cb(null); cb(null);
} }
}); });
}); });
}; };
@ -702,7 +702,7 @@ function Packet(options) {
// //
// message: unbound length, NULL term'd // message: unbound length, NULL term'd
// //
// We need to build in various special lines - kludges, area, // We need to build in various special lines - kludges, area,
// seen-by, etc. // seen-by, etc.
// //
@ -716,7 +716,7 @@ function Packet(options) {
if(message.meta.FtnProperty.ftn_area) { if(message.meta.FtnProperty.ftn_area) {
msgBody += `AREA:${message.meta.FtnProperty.ftn_area}\r`; // note: no ^A (0x01) msgBody += `AREA:${message.meta.FtnProperty.ftn_area}\r`; // note: no ^A (0x01)
} }
// :TODO: DRY with similar function in this file! // :TODO: DRY with similar function in this file!
Object.keys(message.meta.FtnKludge).forEach(k => { Object.keys(message.meta.FtnKludge).forEach(k => {
switch(k) { switch(k) {
@ -731,7 +731,7 @@ function Packet(options) {
break; break;
default : default :
msgBody += getAppendMeta(`\x01${k}`, message.meta.FtnKludge[k]); msgBody += getAppendMeta(`\x01${k}`, message.meta.FtnKludge[k]);
break; break;
} }
}); });
@ -780,22 +780,22 @@ function Packet(options) {
// //
msgBody += getAppendMeta('SEEN-BY', message.meta.FtnProperty.ftn_seen_by); // note: no ^A (0x01) msgBody += getAppendMeta('SEEN-BY', message.meta.FtnProperty.ftn_seen_by); // note: no ^A (0x01)
msgBody += getAppendMeta('\x01PATH', message.meta.FtnKludge['PATH']); msgBody += getAppendMeta('\x01PATH', message.meta.FtnKludge['PATH']);
let msgBodyEncoded; let msgBodyEncoded;
try { try {
msgBodyEncoded = iconv.encode(msgBody + '\0', options.encoding); msgBodyEncoded = iconv.encode(msgBody + '\0', options.encoding);
} catch(e) { } catch(e) {
msgBodyEncoded = iconv.encode(msgBody + '\0', 'ascii'); msgBodyEncoded = iconv.encode(msgBody + '\0', 'ascii');
} }
return callback( return callback(
null, null,
Buffer.concat( [ Buffer.concat( [
basicHeader, basicHeader,
toUserNameBuf, toUserNameBuf,
fromUserNameBuf, fromUserNameBuf,
subjectBuf, subjectBuf,
msgBodyEncoded msgBodyEncoded
]) ])
); );
} }
@ -808,7 +808,7 @@ function Packet(options) {
this.writeMessage = function(message, ws, options) { this.writeMessage = function(message, ws, options) {
let basicHeader = new Buffer(34); let basicHeader = new Buffer(34);
basicHeader.writeUInt16LE(FTN_PACKET_MESSAGE_TYPE, 0); basicHeader.writeUInt16LE(FTN_PACKET_MESSAGE_TYPE, 0);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_orig_node, 2); basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_orig_node, 2);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_dest_node, 4); 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); let encBuf = iconv.encode(message.toUserName + '\0', 'CP437').slice(0, 36);
encBuf[encBuf.length - 1] = '\0'; // ensure it's null term'd encBuf[encBuf.length - 1] = '\0'; // ensure it's null term'd
ws.write(encBuf); ws.write(encBuf);
encBuf = iconv.encode(message.fromUserName + '\0', 'CP437').slice(0, 36); encBuf = iconv.encode(message.fromUserName + '\0', 'CP437').slice(0, 36);
encBuf[encBuf.length - 1] = '\0'; // ensure it's null term'd encBuf[encBuf.length - 1] = '\0'; // ensure it's null term'd
ws.write(encBuf); ws.write(encBuf);
@ -839,7 +839,7 @@ function Packet(options) {
// //
// message: unbound length, NULL term'd // message: unbound length, NULL term'd
// //
// We need to build in various special lines - kludges, area, // We need to build in various special lines - kludges, area,
// seen-by, etc. // seen-by, etc.
// //
@ -866,7 +866,7 @@ function Packet(options) {
if(message.meta.FtnProperty.ftn_area) { if(message.meta.FtnProperty.ftn_area) {
msgBody += `AREA:${message.meta.FtnProperty.ftn_area}\r`; // note: no ^A (0x01) msgBody += `AREA:${message.meta.FtnProperty.ftn_area}\r`; // note: no ^A (0x01)
} }
Object.keys(message.meta.FtnKludge).forEach(k => { Object.keys(message.meta.FtnKludge).forEach(k => {
switch(k) { switch(k) {
case 'PATH' : break; // skip & save for last case 'PATH' : break; // skip & save for last
@ -889,8 +889,8 @@ function Packet(options) {
if(message.meta.FtnProperty.ftn_tear_line) { if(message.meta.FtnProperty.ftn_tear_line) {
msgBody += `${message.meta.FtnProperty.ftn_tear_line}\r`; msgBody += `${message.meta.FtnProperty.ftn_tear_line}\r`;
} }
// //
// Origin line should be near the bottom of a message // Origin line should be near the bottom of a message
// //
if(message.meta.FtnProperty.ftn_origin) { if(message.meta.FtnProperty.ftn_origin) {
@ -918,11 +918,11 @@ function Packet(options) {
if(err) { if(err) {
return callback(err); return callback(err);
} }
let next = function(e) { let next = function(e) {
callback(e); callback(e);
}; };
iterator('header', header, next); iterator('header', header, next);
}); });
}, },
@ -934,7 +934,7 @@ function Packet(options) {
} }
], ],
cb // complete cb // complete
); );
}; };
} }
@ -954,7 +954,7 @@ Packet.Attribute = {
InTransit : 0x0020, InTransit : 0x0020,
Orphan : 0x0040, Orphan : 0x0040,
KillSent : 0x0080, KillSent : 0x0080,
Local : 0x0100, // Message is from *this* system Local : 0x0100, // Message is from *this* system
Hold : 0x0200, Hold : 0x0200,
Reserved0 : 0x0400, Reserved0 : 0x0400,
FileRequest : 0x0800, FileRequest : 0x0800,
@ -998,7 +998,7 @@ Packet.prototype.writeHeader = function(ws, packetHeader) {
Packet.prototype.writeMessageEntry = function(ws, msgEntry) { Packet.prototype.writeMessageEntry = function(ws, msgEntry) {
ws.write(msgEntry); ws.write(msgEntry);
return msgEntry.length; return msgEntry.length;
}; };
Packet.prototype.writeTerminator = function(ws) { Packet.prototype.writeTerminator = function(ws) {
@ -1014,11 +1014,11 @@ Packet.prototype.writeStream = function(ws, messages, options) {
if(!_.isBoolean(options.terminatePacket)) { if(!_.isBoolean(options.terminatePacket)) {
options.terminatePacket = true; options.terminatePacket = true;
} }
if(_.isObject(options.packetHeader)) { if(_.isObject(options.packetHeader)) {
this.writePacketHeader(options.packetHeader, ws); this.writePacketHeader(options.packetHeader, ws);
} }
options.encoding = options.encoding || 'utf8'; options.encoding = options.encoding || 'utf8';
messages.forEach(msg => { messages.forEach(msg => {
@ -1034,12 +1034,12 @@ Packet.prototype.write = function(path, packetHeader, messages, options) {
if(!_.isArray(messages)) { if(!_.isArray(messages)) {
messages = [ messages ]; messages = [ messages ];
} }
options = options || { encoding : 'utf8' }; // utf-8 = 'CHRS UTF-8 4' options = options || { encoding : 'utf8' }; // utf-8 = 'CHRS UTF-8 4'
this.writeStream( this.writeStream(
fs.createWriteStream(path), // :TODO: specify mode/etc. fs.createWriteStream(path), // :TODO: specify mode/etc.
messages, 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 // 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 buffer = new Buffer(bufLen).fill(0x00);
let enc = iconv.encode(s, 'CP437').slice(0, bufLen); let enc = iconv.encode(s, 'CP437').slice(0, bufLen);
for(let i = 0; i < enc.length; ++i) { 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 // Convert a FTN style DateTime string to a Date object
// //
// :TODO: Name the next couple methods better - for FTN *packets* // :TODO: Name the next couple methods better - for FTN *packets*
function getDateFromFtnDateTime(dateTime) { function getDateFromFtnDateTime(dateTime) {
// //
@ -103,7 +103,7 @@ function getMessageSerialNumber(messageId) {
// //
// Return a FTS-0009.001 compliant MSGID value given a message // Return a FTS-0009.001 compliant MSGID value given a message
// See http://ftsc.org/docs/fts-0009.001 // See http://ftsc.org/docs/fts-0009.001
// //
// "A MSGID line consists of the string "^AMSGID:" (where ^A is a // "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 // control-A (hex 01) and the double-quotes are not part of the
// string), followed by a space, the address of the originating // string), followed by a space, the address of the originating
@ -113,9 +113,9 @@ function getMessageSerialNumber(messageId) {
// ^AMSGID: origaddr serialno // ^AMSGID: origaddr serialno
// //
// The originating address should be specified in a form that // 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 // 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 // considered to be the orginating address. A double-quote character
// within a quoted address is represented by by two consecutive // within a quoted address is represented by by two consecutive
// double-quote characters. The serial number may be any eight // 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 // messages from a given system may have the same serial number
// within a three years. The manner in which this serial number is // within a three years. The manner in which this serial number is
// generated is left to the implementor." // generated is left to the implementor."
// //
// //
// Examples & Implementations // Examples & Implementations
// //
// Synchronet: <msgNum>.<conf+area>@<ftnAddr> <serial> // Synchronet: <msgNum>.<conf+area>@<ftnAddr> <serial>
// 2606.agora-agn_tst@46:1/142 19609217 // 2606.agora-agn_tst@46:1/142 19609217
// //
// Mystic: <ftnAddress> <serial> // Mystic: <ftnAddress> <serial>
// 46:3/102 46686263 // 46:3/102 46686263
// //
@ -145,10 +145,10 @@ function getMessageSerialNumber(messageId) {
// //
function getMessageIdentifier(message, address, isNetMail = false) { function getMessageIdentifier(message, address, isNetMail = false) {
const addrStr = new Address(address).toString('5D'); const addrStr = new Address(address).toString('5D');
return isNetMail ? return isNetMail ?
`${addrStr} ${getMessageSerialNumber(message.messageId)}` : `${addrStr} ${getMessageSerialNumber(message.messageId)}` :
`${message.messageId}.${message.areaTag.toLowerCase()}@${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 // 'TZUTC' kludge line
// //
// http://ftsc.org/docs/frl-1004.002 // http://ftsc.org/docs/frl-1004.002
@ -178,10 +178,10 @@ function getUTCTimeZoneOffset() {
// //
// Get a FSC-0032 style quote prefix // Get a FSC-0032 style quote prefix
// http://ftsc.org/docs/fsc-0032.001 // http://ftsc.org/docs/fsc-0032.001
// //
function getQuotePrefix(name) { function getQuotePrefix(name) {
let initials; let initials;
const parts = name.split(' '); const parts = name.split(' ');
if(parts.length > 1) { if(parts.length > 1) {
// First & Last initials - (Bryan Ashby -> BA) // First & Last initials - (Bryan Ashby -> BA)
@ -199,7 +199,7 @@ function getQuotePrefix(name) {
// http://ftsc.org/docs/fts-0004.001 // http://ftsc.org/docs/fts-0004.001
// //
function getOrigin(address) { function getOrigin(address) {
const origin = _.has(Config, 'messageNetworks.originLine') ? const origin = _.has(Config, 'messageNetworks.originLine') ?
Config.messageNetworks.originLine : Config.messageNetworks.originLine :
Config.general.boardName; Config.general.boardName;
@ -220,16 +220,12 @@ function getVia(address) {
/* /*
FRL-1005.001 states teh following format: 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> <Program Name> <Version> [Serial Number]<CR>
*/ */
const addrStr = new Address(address).toString('5D'); const addrStr = new Address(address).toString('5D');
const dateTime = moment().utc().format('YYYYMMDD.HHmmSS.SSSS.UTC'); const dateTime = moment().utc().format('YYYYMMDD.HHmmSS.SSSS.UTC');
const version = getCleanEnigmaVersion();
const version = packageJson.version
.replace(/\-/g, '.')
.replace(/alpha/,'a')
.replace(/beta/,'b');
return `${addrStr} @${dateTime} ENiGMA1/2 ${version}`; return `${addrStr} @${dateTime} ENiGMA1/2 ${version}`;
} }
@ -272,7 +268,7 @@ function parseAbbreviatedNetNodeList(netNodes) {
const re = /([0-9]+)\/([0-9]+)\s?|([0-9]+)\s?/g; const re = /([0-9]+)\/([0-9]+)\s?|([0-9]+)\s?/g;
let net; let net;
let m; let m;
let results = []; let results = [];
while(null !== (m = re.exec(netNodes))) { while(null !== (m = re.exec(netNodes))) {
if(m[1] && m[2]) { if(m[1] && m[2]) {
net = parseInt(m[1]); net = parseInt(m[1]);
@ -288,7 +284,7 @@ function parseAbbreviatedNetNodeList(netNodes) {
// //
// Return a FTS-0004.001 SEEN-BY entry(s) that include // Return a FTS-0004.001 SEEN-BY entry(s) that include
// all pre-existing SEEN-BY entries with the addition // all pre-existing SEEN-BY entries with the addition
// of |additions|. // of |additions|.
// //
// See http://ftsc.org/docs/fts-0004.001 // See http://ftsc.org/docs/fts-0004.001
// and notes at http://ftsc.org/docs/fsc-0043.002. // and notes at http://ftsc.org/docs/fsc-0043.002.
@ -324,9 +320,9 @@ function getUpdatedSeenByEntries(existingEntries, additions) {
if(!_.isArray(existingEntries)) { if(!_.isArray(existingEntries)) {
existingEntries = [ existingEntries ]; existingEntries = [ existingEntries ];
} }
if(!_.isString(additions)) { if(!_.isString(additions)) {
additions = parseAbbreviatedNetNodeList(getAbbreviatedNetNodeList(additions)); additions = parseAbbreviatedNetNodeList(getAbbreviatedNetNodeList(additions));
} }
additions = additions.sort(Address.getComparator()); additions = additions.sort(Address.getComparator());
@ -361,13 +357,13 @@ const ENCODING_TO_FTS_5003_001_CHARS = {
// level 1 - generally should not be used // level 1 - generally should not be used
ascii : [ 'ASCII', 1 ], ascii : [ 'ASCII', 1 ],
'us-ascii' : [ 'ASCII', 1 ], 'us-ascii' : [ 'ASCII', 1 ],
// level 2 - 8 bit, ASCII based // level 2 - 8 bit, ASCII based
cp437 : [ 'CP437', 2 ], cp437 : [ 'CP437', 2 ],
cp850 : [ 'CP850', 2 ], cp850 : [ 'CP850', 2 ],
// level 3 - reserved // level 3 - reserved
// level 4 // level 4
utf8 : [ 'UTF-8', 4 ], utf8 : [ 'UTF-8', 4 ],
'utf-8' : [ 'UTF-8', 4 ], 'utf-8' : [ 'UTF-8', 4 ],
@ -381,7 +377,7 @@ function getCharacterSetIdentifierByEncoding(encodingName) {
function getEncodingFromCharacterSetIdentifier(chrs) { function getEncodingFromCharacterSetIdentifier(chrs) {
const ident = chrs.split(' ')[0].toUpperCase(); const ident = chrs.split(' ')[0].toUpperCase();
// :TODO: fill in the rest!!! // :TODO: fill in the rest!!!
return { return {
// level 1 // level 1
@ -399,7 +395,7 @@ function getEncodingFromCharacterSetIdentifier(chrs) {
'SWISS' : 'iso-646', 'SWISS' : 'iso-646',
'UK' : 'iso-646', 'UK' : 'iso-646',
'ISO-10' : 'iso-646-10', 'ISO-10' : 'iso-646-10',
// level 2 // level 2
'CP437' : 'cp437', 'CP437' : 'cp437',
'CP850' : 'cp850', 'CP850' : 'cp850',
@ -414,15 +410,15 @@ function getEncodingFromCharacterSetIdentifier(chrs) {
'LATIN-2' : 'iso-8859-2', 'LATIN-2' : 'iso-8859-2',
'LATIN-5' : 'iso-8859-9', 'LATIN-5' : 'iso-8859-9',
'LATIN-9' : 'iso-8859-15', 'LATIN-9' : 'iso-8859-15',
// level 4 // level 4
'UTF-8' : 'utf8', 'UTF-8' : 'utf8',
// deprecated stuff // deprecated stuff
'IBMPC' : 'cp1250', // :TODO: validate 'IBMPC' : 'cp1250', // :TODO: validate
'+7_FIDO' : 'cp866', '+7_FIDO' : 'cp866',
'+7' : 'cp866', '+7' : 'cp866',
'MAC' : 'macroman', // :TODO: validate 'MAC' : 'macroman', // :TODO: validate
}[ident]; }[ident];
} }

View File

@ -63,7 +63,7 @@ function HorizontalMenuView(options) {
} }
var text = strUtil.stylizeString( var text = strUtil.stylizeString(
item.text, item.text,
this.hasFocus && item.focused ? self.focusTextStyle : self.textStyle); this.hasFocus && item.focused ? self.focusTextStyle : self.textStyle);
var drawWidth = text.length + self.getSpacer().length * 2; // * 2 = sides var drawWidth = text.length + self.getSpacer().length * 2; // * 2 = sides
@ -72,7 +72,7 @@ function HorizontalMenuView(options) {
ansi.goto(self.position.row, item.col) + ansi.goto(self.position.row, item.col) +
(index === self.focusedItemIndex ? self.getFocusSGR() : self.getSGR()) + (index === self.focusedItemIndex ? self.getFocusSGR() : self.getSGR()) +
strUtil.pad(text, drawWidth, self.fillChar, 'center') 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) { if(key && 'tab' === key.name && !this.eatTabKey) {
return this.emit('action', 'next', key); return this.emit('action', 'next', key);
} }
this.emit('action', 'accept'); this.emit('action', 'accept');
// NOTE: we don't call super here. KeyEntryView is a special snowflake. // NOTE: we don't call super here. KeyEntryView is a special snowflake.
} }
@ -69,7 +69,7 @@ module.exports = class KeyEntryView extends View {
} }
break; break;
} }
super.setPropertyValue(propName, propValue); super.setPropertyValue(propName, propValue);
} }

View File

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

View File

@ -12,7 +12,7 @@ module.exports = class Log {
static init() { static init() {
const Config = require('./config.js').config; const Config = require('./config.js').config;
const logPath = Config.paths.logs; const logPath = Config.paths.logs;
const err = this.checkLogPath(logPath); const err = this.checkLogPath(logPath);
if(err) { if(err) {
console.error(err.message); // eslint-disable-line no-console 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. 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 => { [ 'formData', 'formValue' ].forEach(keyName => {
serializers[keyName] = (fd) => Log.hideSensitive(fd); serializers[keyName] = (fd) => Log.hideSensitive(fd);
}); });
this.log = bunyan.createLogger({ this.log = bunyan.createLogger({
@ -46,7 +46,7 @@ module.exports = class Log {
if(!fs.statSync(logPath).isDirectory()) { if(!fs.statSync(logPath).isDirectory()) {
return new Error(`${logPath} is not a directory`); return new Error(`${logPath} is not a directory`);
} }
return null; return null;
} catch(e) { } catch(e) {
if('ENOENT' === e.code) { if('ENOENT' === e.code) {

View File

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

View File

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

View File

@ -6,7 +6,7 @@ const Message = require('./message.js');
exports.getAddressedToInfo = getAddressedToInfo; 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 Input Output

View File

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

View File

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

View File

@ -17,17 +17,17 @@ const assert = require('assert');
const _ = require('lodash'); const _ = require('lodash');
exports.MenuModule = class MenuModule extends PluginModule { exports.MenuModule = class MenuModule extends PluginModule {
constructor(options) { constructor(options) {
super(options); super(options);
this.menuName = options.menuName; this.menuName = options.menuName;
this.menuConfig = options.menuConfig; this.menuConfig = options.menuConfig;
this.client = options.client; this.client = options.client;
this.menuConfig.options = options.menuConfig.options || {}; 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.menuConfig.config = this.menuConfig.config || {};
this.cls = _.isBoolean(this.menuConfig.options.cls) ? this.menuConfig.options.cls : Config.menus.cls; this.cls = _.isBoolean(this.menuConfig.options.cls) ? this.menuConfig.options.cls : Config.menus.cls;
this.viewControllers = {}; this.viewControllers = {};
@ -70,7 +70,7 @@ exports.MenuModule = class MenuModule extends PluginModule {
} }
); );
}, },
function moveToPromptLocation(callback) { function moveToPromptLocation(callback) {
if(self.menuConfig.prompt) { if(self.menuConfig.prompt) {
// :TODO: fetch and move cursor to prompt location, if supplied. See notes/etc. on placements // :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) { nextMenu(cb) {
if(!this.haveNext()) { if(!this.haveNext()) {
return this.prevMenu(cb); // no next, go to prev return this.prevMenu(cb); // no next, go to prev
} }
return this.client.menuStack.next(cb); return this.client.menuStack.next(cb);
} }
@ -210,7 +210,7 @@ exports.MenuModule = class MenuModule extends PluginModule {
haveNext() { haveNext() {
return (_.isString(this.menuConfig.next) || _.isArray(this.menuConfig.next)); return (_.isString(this.menuConfig.next) || _.isArray(this.menuConfig.next));
} }
autoNextMenu(cb) { autoNextMenu(cb) {
const self = this; const self = this;
@ -221,8 +221,8 @@ exports.MenuModule = class MenuModule extends PluginModule {
return self.prevMenu(cb); 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()) { if(this.hasNextTimeout()) {
setTimeout( () => { setTimeout( () => {
return gotoNextMenu(); return gotoNextMenu();
@ -297,10 +297,10 @@ exports.MenuModule = class MenuModule extends PluginModule {
if(options.clearScreen) { if(options.clearScreen) {
this.client.term.rawWrite(ansi.resetScreen()); this.client.term.rawWrite(ansi.resetScreen());
} }
return theme.displayThemedAsset( return theme.displayThemedAsset(
name, name,
this.client, this.client,
Object.assign( { font : this.menuConfig.config.font }, options ), Object.assign( { font : this.menuConfig.config.font }, options ),
(err, artData) => { (err, artData) => {
if(cb) { if(cb) {
@ -361,7 +361,7 @@ exports.MenuModule = class MenuModule extends PluginModule {
pausePrompt(position, cb) { pausePrompt(position, cb) {
if(!cb && _.isFunction(position)) { if(!cb && _.isFunction(position)) {
cb = position; cb = position;
position = null; position = null;
} }
this.optionalMoveToPosition(position); this.optionalMoveToPosition(position);
@ -390,7 +390,7 @@ exports.MenuModule = class MenuModule extends PluginModule {
if(!view) { if(!view) {
return; return;
} }
if(appendMultiLine && (view instanceof MultiLineEditTextView)) { if(appendMultiLine && (view instanceof MultiLineEditTextView)) {
view.addText(text); view.addText(text);
} else { } else {
@ -401,7 +401,7 @@ exports.MenuModule = class MenuModule extends PluginModule {
updateCustomViewTextsWithFilter(formName, startId, fmtObj, options) { updateCustomViewTextsWithFilter(formName, startId, fmtObj, options) {
options = options || {}; options = options || {};
let textView; let textView;
let customMciId = startId; let customMciId = startId;
const config = this.menuConfig.config; const config = this.menuConfig.config;
const endId = options.endId || 99; // we'll fail to get a view before 99 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... // :TODO: leave() should really take a cb...
this.pop().instance.leave(); // leave & remove current this.pop().instance.leave(); // leave & remove current
const previousModuleInfo = this.pop(); // get previous const previousModuleInfo = this.pop(); // get previous
if(previousModuleInfo) { if(previousModuleInfo) {
const opts = { const opts = {
extraArgs : previousModuleInfo.extraArgs, extraArgs : previousModuleInfo.extraArgs,
savedState : previousModuleInfo.savedState, savedState : previousModuleInfo.savedState,
lastMenuResult : menuResult, lastMenuResult : menuResult,
}; };
return this.goto(previousModuleInfo.name, opts, cb); return this.goto(previousModuleInfo.name, opts, cb);
} }
return cb(Errors.MenuStack('No previous menu available', 'NOPREV')); return cb(Errors.MenuStack('No previous menu available', 'NOPREV'));
} }
@ -106,14 +106,14 @@ module.exports = class MenuStack {
if(currentModuleInfo && name === currentModuleInfo.name) { if(currentModuleInfo && name === currentModuleInfo.name) {
if(cb) { if(cb) {
cb(Errors.MenuStack('Already at supplied menu', 'ALREADYTHERE')); cb(Errors.MenuStack('Already at supplied menu', 'ALREADYTHERE'));
} }
return; return;
} }
const loadOpts = { const loadOpts = {
name : name, name : name,
client : self.client, client : self.client,
}; };
if(_.isObject(options)) { if(_.isObject(options)) {

View File

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

View File

@ -16,7 +16,7 @@ exports.MenuView = MenuView;
function MenuView(options) { function MenuView(options) {
options.acceptsFocus = miscUtil.valueWithDefault(options.acceptsFocus, true); options.acceptsFocus = miscUtil.valueWithDefault(options.acceptsFocus, true);
options.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true); options.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true);
View.call(this, options); View.call(this, options);
this.disablePipe = options.disablePipe || false; this.disablePipe = options.disablePipe || false;
@ -65,11 +65,11 @@ util.inherits(MenuView, View);
MenuView.prototype.setItems = function(items) { MenuView.prototype.setItems = function(items) {
const self = this; const self = this;
if(items) { if(items) {
this.items = []; this.items = [];
items.forEach( itemText => { items.forEach( itemText => {
this.items.push( this.items.push(
{ {
text : self.disablePipe ? itemText : pipeToAnsi(itemText, self.client) text : self.disablePipe ? itemText : pipeToAnsi(itemText, self.client)
} }
); );
@ -79,7 +79,7 @@ MenuView.prototype.setItems = function(items) {
MenuView.prototype.removeItem = function(index) { MenuView.prototype.removeItem = function(index) {
this.items.splice(index, 1); this.items.splice(index, 1);
if(this.focusItems) { if(this.focusItems) {
this.focusItems.splice(index, 1); this.focusItems.splice(index, 1);
} }
@ -95,7 +95,7 @@ MenuView.prototype.getCount = function() {
return this.items.length; return this.items.length;
}; };
MenuView.prototype.getItems = function() { MenuView.prototype.getItems = function() {
return this.items.map( item => { return this.items.map( item => {
return item.text; return item.text;
}); });
@ -140,7 +140,7 @@ MenuView.prototype.onKeyPress = function(ch, key) {
MenuView.prototype.setFocusItems = function(items) { MenuView.prototype.setFocusItems = function(items) {
const self = this; const self = this;
if(items) { if(items) {
this.focusItems = []; this.focusItems = [];
items.forEach( itemText => { items.forEach( itemText => {
@ -183,7 +183,7 @@ MenuView.prototype.setHotKeys = function(hotKeys) {
this.hotKeys[key.toLowerCase()] = hotKeys[key]; this.hotKeys[key.toLowerCase()] = hotKeys[key];
} }
} else { } 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 Errors = require('./enig_error.js').Errors;
const ANSI = require('./ansi_term.js'); const ANSI = require('./ansi_term.js');
const { const {
isAnsi, isFormattedLine, isAnsi, isFormattedLine,
splitTextAtTerms, splitTextAtTerms,
renderSubstr renderSubstr
} = require('./string_util.js'); } = require('./string_util.js');
@ -45,7 +45,7 @@ function Message(options) {
this.fromUserName = options.fromUserName || ''; this.fromUserName = options.fromUserName || '';
this.subject = options.subject || ''; this.subject = options.subject || '';
this.message = options.message || ''; this.message = options.message || '';
if(_.isDate(options.modTimestamp) || moment.isMoment(options.modTimestamp)) { if(_.isDate(options.modTimestamp) || moment.isMoment(options.modTimestamp)) {
this.modTimestamp = moment(options.modTimestamp); this.modTimestamp = moment(options.modTimestamp);
} else if(_.isString(options.modTimestamp)) { } else if(_.isString(options.modTimestamp)) {
@ -115,7 +115,7 @@ Message.StateFlags0 = {
Exported : 0x00000002, // exported to foreign system Exported : 0x00000002, // exported to foreign system
}; };
Message.FtnPropertyNames = { Message.FtnPropertyNames = {
FtnOrigNode : 'ftn_orig_node', FtnOrigNode : 'ftn_orig_node',
FtnDestNode : 'ftn_dest_node', FtnDestNode : 'ftn_dest_node',
FtnOrigNetwork : 'ftn_orig_network', FtnOrigNetwork : 'ftn_orig_network',
@ -166,12 +166,12 @@ Message.createMessageUUID = function(areaTag, modTimestamp, subject, body) {
if(!moment.isMoment(modTimestamp)) { if(!moment.isMoment(modTimestamp)) {
modTimestamp = moment(modTimestamp); modTimestamp = moment(modTimestamp);
} }
areaTag = iconvEncode(areaTag.toUpperCase(), 'CP437'); areaTag = iconvEncode(areaTag.toUpperCase(), 'CP437');
modTimestamp = iconvEncode(modTimestamp.format('DD MMM YY HH:mm:ss'), 'CP437'); modTimestamp = iconvEncode(modTimestamp.format('DD MMM YY HH:mm:ss'), 'CP437');
subject = iconvEncode(subject.toUpperCase().trim(), 'CP437'); subject = iconvEncode(subject.toUpperCase().trim(), 'CP437');
body = iconvEncode(body.replace(/\r\n|[\n\v\f\r\x85\u2028\u2029]/g, '').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 ] ))); 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 `SELECT message_id
FROM message FROM message
WHERE message_uuid = ? WHERE message_uuid = ?
LIMIT 1;`, LIMIT 1;`,
[ uuid ], [ uuid ],
(err, row) => { (err, row) => {
if(err) { if(err) {
cb(err); cb(err);
@ -210,30 +210,30 @@ Message.getMessageIdsByMetaValue = function(category, name, value, cb) {
}; };
Message.getMetaValuesByMessageId = function(messageId, category, name, cb) { Message.getMetaValuesByMessageId = function(messageId, category, name, cb) {
const sql = const sql =
`SELECT meta_value `SELECT meta_value
FROM message_meta FROM message_meta
WHERE message_id = ? AND meta_category = ? AND meta_name = ?;`; WHERE message_id = ? AND meta_category = ? AND meta_name = ?;`;
msgDb.all(sql, [ messageId, category, name ], (err, rows) => { msgDb.all(sql, [ messageId, category, name ], (err, rows) => {
if(err) { if(err) {
return cb(err); return cb(err);
} }
if(0 === rows.length) { if(0 === rows.length) {
return cb(new Error('No value for category/name')); return cb(new Error('No value for category/name'));
} }
// single values are returned without an array // single values are returned without an array
if(1 === rows.length) { if(1 === rows.length) {
return cb(null, rows[0].meta_value); return cb(null, rows[0].meta_value);
} }
cb(null, rows.map(r => r.meta_value)); // map to array of values only 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( async.waterfall(
[ [
function getMessageId(callback) { function getMessageId(callback) {
@ -256,22 +256,22 @@ Message.getMetaValuesByMessageUuid = function(uuid, category, name, cb) {
Message.prototype.loadMeta = function(cb) { Message.prototype.loadMeta = function(cb) {
/* /*
Example of loaded this.meta: Example of loaded this.meta:
meta: { meta: {
System: { System: {
local_to_user_id: 1234, local_to_user_id: 1234,
}, },
FtnProperty: { FtnProperty: {
ftn_seen_by: [ "1/102 103", "2/42 52 65" ] ftn_seen_by: [ "1/102 103", "2/42 52 65" ]
} }
} }
*/ */
const sql = const sql =
`SELECT meta_category, meta_name, meta_value `SELECT meta_category, meta_name, meta_value
FROM message_meta FROM message_meta
WHERE message_id = ?;`; WHERE message_id = ?;`;
let self = this; let self = this;
msgDb.each(sql, [ this.messageId ], (err, row) => { msgDb.each(sql, [ this.messageId ], (err, row) => {
if(!(row.meta_category in self.meta)) { 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; self.meta[row.meta_category][row.meta_name] = row.meta_value;
} else { } else {
if(!(row.meta_name in self.meta[row.meta_category])) { 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 { } else {
if(_.isString(self.meta[row.meta_category][row.meta_name])) { 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); self.meta[row.meta_category][row.meta_name].push(row.meta_value);
} }
} }
@ -315,7 +315,7 @@ Message.prototype.load = function(options, cb) {
if(!msgRow) { if(!msgRow) {
return callback(new Error('Message (no longer) available')); return callback(new Error('Message (no longer) available'));
} }
self.messageId = msgRow.message_id; self.messageId = msgRow.message_id;
self.areaTag = msgRow.area_tag; self.areaTag = msgRow.area_tag;
self.messageUuid = msgRow.message_uuid; self.messageUuid = msgRow.message_uuid;
@ -356,13 +356,13 @@ Message.prototype.persistMetaValue = function(category, name, value, transOrDb,
const metaStmt = transOrDb.prepare( const metaStmt = transOrDb.prepare(
`INSERT INTO message_meta (message_id, meta_category, meta_name, meta_value) `INSERT INTO message_meta (message_id, meta_category, meta_name, meta_value)
VALUES (?, ?, ?, ?);`); VALUES (?, ?, ?, ?);`);
if(!_.isArray(value)) { if(!_.isArray(value)) {
value = [ value ]; value = [ value ];
} }
let self = this; let self = this;
async.each(value, (v, next) => { async.each(value, (v, next) => {
metaStmt.run(self.messageId, category, name, v, err => { metaStmt.run(self.messageId, category, name, v, err => {
next(err); next(err);
@ -379,7 +379,7 @@ Message.prototype.persist = function(cb) {
} }
const self = this; const self = this;
async.waterfall( async.waterfall(
[ [
function beginTransaction(callback) { function beginTransaction(callback) {
@ -398,7 +398,7 @@ Message.prototype.persist = function(cb) {
trans.run( trans.run(
`INSERT INTO message (area_tag, message_uuid, reply_to_message_id, to_user_name, from_user_name, subject, message, modified_timestamp) `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) ], [ 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 function inserted(err) { // use non-arrow function for 'this' scope
if(!err) { if(!err) {
@ -415,15 +415,15 @@ Message.prototype.persist = function(cb) {
} }
/* /*
Example of self.meta: Example of self.meta:
meta: { meta: {
System: { System: {
local_to_user_id: 1234, local_to_user_id: 1234,
}, },
FtnProperty: { FtnProperty: {
ftn_seen_by: [ "1/102 103", "2/42 52 65" ] 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, nextCat) => {
async.each(Object.keys(self.meta[category]), (name, nextName) => { async.each(Object.keys(self.meta[category]), (name, nextName) => {
@ -433,10 +433,10 @@ Message.prototype.persist = function(cb) {
}, err => { }, err => {
nextCat(err); nextCat(err);
}); });
}, err => { }, err => {
callback(err, trans); callback(err, trans);
}); });
}, },
function storeHashTags(trans, callback) { function storeHashTags(trans, callback) {
// :TODO: hash tag support // :TODO: hash tag support
@ -470,21 +470,21 @@ Message.prototype.getQuoteLines = function(options, cb) {
if(!options.termWidth || !options.termHeight || !options.cols) { if(!options.termWidth || !options.termHeight || !options.cols) {
return cb(Errors.MissingParam()); return cb(Errors.MissingParam());
} }
options.startCol = options.startCol || 1; options.startCol = options.startCol || 1;
options.includePrefix = _.get(options, 'includePrefix', true); options.includePrefix = _.get(options, 'includePrefix', true);
options.ansiResetSgr = options.ansiResetSgr || ANSI.getSGRFromGraphicRendition( { fg : 39, bg : 49 }, 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.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 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 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 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 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', tabHandling : 'expand',
tabWidth : 4, tabWidth : 4,
}; };
return wordWrapText(text, wrapOpts).wrapped.map( (w, i) => { return wordWrapText(text, wrapOpts).wrapped.map( (w, i) => {
return i === 0 ? `${quotePrefix}${w}` : `${quotePrefix}${extraPrefix}${w}`; return i === 0 ? `${quotePrefix}${w}` : `${quotePrefix}${extraPrefix}${w}`;
}); });
@ -527,44 +527,44 @@ Message.prototype.getQuoteLines = function(options, cb) {
cols : options.cols, cols : options.cols,
rows : 'auto', rows : 'auto',
startCol : options.startCol, startCol : options.startCol,
forceLineTerm : true, forceLineTerm : true,
}, },
(err, prepped) => { (err, prepped) => {
prepped = prepped || this.message; prepped = prepped || this.message;
let lastSgr = ''; let lastSgr = '';
const split = splitTextAtTerms(prepped); const split = splitTextAtTerms(prepped);
const quoteLines = []; const quoteLines = [];
const focusQuoteLines = []; const focusQuoteLines = [];
// //
// Do not include quote prefixes (e.g. XX> ) on ANSI replies (and therefor quote builder) // 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 // strip colors, colorize the lines, etc. If we exclude the prefixes, this seems to do
// the trick and allow them to leave them alone! // the trick and allow them to leave them alone!
// //
split.forEach(l => { split.forEach(l => {
quoteLines.push(`${lastSgr}${l}`); quoteLines.push(`${lastSgr}${l}`);
focusQuoteLines.push(`${options.ansiFocusPrefixSgr}>${lastSgr}${renderSubstr(l, 1, l.length - 1)}`); 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; quoteLines[quoteLines.length - 1] += options.ansiResetSgr;
return cb(null, quoteLines, focusQuoteLines, true); return cb(null, quoteLines, focusQuoteLines, true);
} }
); );
} else { } 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 quoted = [];
const input = _.trimEnd(this.message).replace(/\b/g, ''); const input = _.trimEnd(this.message).replace(/\b/g, '');
// find *last* tearline // find *last* tearline
let tearLinePos = this.getTearLinePosition(input); let tearLinePos = this.getTearLinePosition(input);
tearLinePos = -1 === tearLinePos ? input.length : tearLinePos; // we just want the index or the entire string 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 => { input.slice(0, tearLinePos).split(/\r\n\r\n|\n\n/).forEach(paragraph => {
// //
// For each paragraph, a state machine: // For each paragraph, a state machine:
@ -612,7 +612,7 @@ Message.prototype.getQuoteLines = function(options, cb) {
buf += ` ${line}`; buf += ` ${line}`;
} }
break; break;
case 'quote_line' : case 'quote_line' :
if(quoteMatch) { if(quoteMatch) {
const rem = line.slice(quoteMatch[0].length); const rem = line.slice(quoteMatch[0].length);
@ -628,7 +628,7 @@ Message.prototype.getQuoteLines = function(options, cb) {
state = 'line'; state = 'line';
} }
break; break;
default : default :
if(isFormattedLine(line)) { if(isFormattedLine(line)) {
quoted.push(getFormattedLine(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 buf = 'line' === state ? line : line.replace(/\s/, ''); // trim *first* leading space, if any
} }
break; break;
} }
}); });
quoted.push(...getWrapped(buf, quoteMatch ? quoteMatch[1] : null)); quoted.push(...getWrapped(buf, quoteMatch ? quoteMatch[1] : null));
}); });
input.slice(tearLinePos).split(/\r?\n/).forEach(l => { input.slice(tearLinePos).split(/\r?\n/).forEach(l => {
quoted.push(...getWrapped(l)); quoted.push(...getWrapped(l));
}); });

View File

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

View File

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

View File

@ -36,10 +36,10 @@ function resolvePath(path) {
function getCleanEnigmaVersion() { function getCleanEnigmaVersion() {
return packageJson.version return packageJson.version
.replace(/\-/g, '.') .replace(/-/g, '.')
.replace(/alpha/,'a') .replace(/alpha/,'a')
.replace(/beta/,'b') .replace(/beta/,'b')
; ;
} }
// See also ftn_util.js getTearLine() & getProductIdentifier() // 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 { exports.MessageAreaConfTempSwitcher = Sup => class extends Sup {
tempMessageConfAndAreaSwitch(messageAreaTag) { tempMessageConfAndAreaSwitch(messageAreaTag) {
messageAreaTag = messageAreaTag || this.messageAreaTag; messageAreaTag = messageAreaTag || this.messageAreaTag;
if(!messageAreaTag) { if(!messageAreaTag) {
@ -14,7 +14,7 @@ exports.MessageAreaConfTempSwitcher = Sup => class extends Sup {
this.prevMessageConfAndArea = { this.prevMessageConfAndArea = {
confTag : this.client.user.properties.message_conf_tag, 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)) { if(!messageArea.tempChangeMessageConfAndArea(this.client, this.messageAreaTag)) {
@ -25,7 +25,7 @@ exports.MessageAreaConfTempSwitcher = Sup => class extends Sup {
tempMessageConfAndAreaRestore() { tempMessageConfAndAreaRestore() {
if(this.prevMessageConfAndArea) { if(this.prevMessageConfAndArea) {
this.client.user.properties.message_conf_tag = this.prevMessageConfAndArea.confTag; 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 = { const MciViewIds = {
AreaList : 1, AreaList : 1,
SelAreaInfo1 : 2, SelAreaInfo1 : 2,
SelAreaInfo2 : 3, SelAreaInfo2 : 3,
}; };
exports.getModule = class MessageAreaListModule extends MenuModule { 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.client.term.pipeWrite(`\n|00Cannot change area: ${err.message}\n`);
self.prevMenuOnTimeout(1000, cb); self.prevMenuOnTimeout(1000, cb);
} else { } else {
if(_.isString(area.art)) { if(_.isString(area.art)) {
const dispOptions = { const dispOptions = {
client : self.client, client : self.client,
@ -72,7 +72,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
displayThemeArt(dispOptions, () => { displayThemeArt(dispOptions, () => {
// pause by default, unless explicitly told not to // 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); return self.prevMenuOnTimeout(1000, cb);
} else { } else {
self.pausePrompt( () => { self.pausePrompt( () => {
@ -98,9 +98,9 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
}, timeout); }, timeout);
} }
updateGeneralAreaInfoViews(areaIndex) { // :TODO: these concepts have been replaced with the {someKey} style formatting - update me!
// :TODO: these concepts have been replaced with the {someKey} style formatting - update me! /*
/* experimental: not yet avail updateGeneralAreaInfoViews(areaIndex) {
const areaInfo = self.messageAreas[areaIndex]; const areaInfo = self.messageAreas[areaIndex];
[ MciViewIds.SelAreaInfo1, MciViewIds.SelAreaInfo2 ].forEach(mciId => { [ MciViewIds.SelAreaInfo1, MciViewIds.SelAreaInfo2 ].forEach(mciId => {
@ -109,8 +109,8 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
v.setFormatObject(areaInfo.area); v.setFormatObject(areaInfo.area);
} }
}); });
*/
} }
*/
mciReady(mciData, cb) { mciReady(mciData, cb) {
super.mciReady(mciData, err => { super.mciReady(mciData, err => {
@ -137,7 +137,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
function populateAreaListView(callback) { function populateAreaListView(callback) {
const listFormat = self.menuConfig.config.listFormat || '{index} ) - {name}'; const listFormat = self.menuConfig.config.listFormat || '{index} ) - {name}';
const focusListFormat = self.menuConfig.config.focusListFormat || listFormat; const focusListFormat = self.menuConfig.config.focusListFormat || listFormat;
const areaListView = vc.getView(MciViewIds.AreaList); const areaListView = vc.getView(MciViewIds.AreaList);
let i = 1; let i = 1;
areaListView.setItems(_.map(self.messageAreas, v => { areaListView.setItems(_.map(self.messageAreas, v => {
@ -145,7 +145,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
index : i++, index : i++,
areaTag : v.area.areaTag, areaTag : v.area.areaTag,
name : v.area.name, name : v.area.name,
desc : v.area.desc, desc : v.area.desc,
}); });
})); }));
@ -155,7 +155,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
index : i++, index : i++,
areaTag : v.area.areaTag, areaTag : v.area.areaTag,
name : v.area.name, 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( self.client.log.info(
{ to : msg.toUserName, subject : msg.subject, uuid : msg.uuid }, { to : msg.toUserName, subject : msg.subject, uuid : msg.uuid },
'Message persisted' 'Message persisted'
); );
} }
return self.nextMenu(cb); return self.nextMenu(cb);
} }
); );

View File

@ -69,7 +69,7 @@ exports.getModule = class AreaViewFSEModule extends FullScreenEditorModule {
case 'down arrow' : bodyView.scrollDocumentUp(); break; case 'down arrow' : bodyView.scrollDocumentUp(); break;
case 'up arrow' : bodyView.scrollDocumentDown(); break; case 'up arrow' : bodyView.scrollDocumentDown(); break;
case 'page up' : bodyView.keyPressPageUp(); 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 // :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 = { const modOpts = {
extraArgs : { extraArgs : {
messageAreaTag : self.messageAreaTag, messageAreaTag : self.messageAreaTag,
replyToMessage : self.message, replyToMessage : self.message,
} }
}; };
return self.gotoMenu(extraArgs.menu, modOpts, cb); return self.gotoMenu(extraArgs.menu, modOpts, cb);
} }
self.client.log(extraArgs, 'Missing extraArgs.menu'); self.client.log(extraArgs, 'Missing extraArgs.menu');
return cb(null); return cb(null);
} }

View File

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

View File

@ -26,7 +26,7 @@ const moment = require('moment');
MCI codes: MCI codes:
VM1 : Message list VM1 : Message list
TL2 : Message info 1: { msgNumSelected, msgNumTotal } TL2 : Message info 1: { msgNumSelected, msgNumTotal }
*/ */
exports.moduleInfo = { 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 // due to the size of |messageList|. See https://github.com/trentm/node-bunyan/issues/189
// //
modOpts.extraArgs.toJSON = function() { modOpts.extraArgs.toJSON = function() {
const logMsgList = (this.messageList.length <= 4) ? const logMsgList = (this.messageList.length <= 4) ?
this.messageList : this.messageList :
this.messageList.slice(0, 2).concat(this.messageList.slice(-2)); this.messageList.slice(0, 2).concat(this.messageList.slice(-2));
return { return {
messageAreaTag : this.messageAreaTag, messageAreaTag : this.messageAreaTag,
@ -158,14 +158,14 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
if(_.isArray(self.messageList)) { if(_.isArray(self.messageList)) {
return callback(0 === self.messageList.length ? new Error('No messages in area') : null); return callback(0 === self.messageList.length ? new Error('No messages in area') : null);
} }
messageArea.getMessageListForArea( { client : self.client }, self.messageAreaTag, function msgs(err, msgList) { messageArea.getMessageListForArea( { client : self.client }, self.messageAreaTag, function msgs(err, msgList) {
if(!msgList || 0 === msgList.length) { if(!msgList || 0 === msgList.length) {
return callback(new Error('No messages in area')); return callback(new Error('No messages in area'));
} }
self.messageList = msgList; self.messageList = msgList;
return callback(err); return callback(err);
}); });
}, },
function getLastReadMesageId(callback) { function getLastReadMesageId(callback) {
@ -187,15 +187,15 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
if(_.isUndefined(self.initialFocusIndex) && listItem.messageId > self.lastReadId) { if(_.isUndefined(self.initialFocusIndex) && listItem.messageId > self.lastReadId) {
self.initialFocusIndex = index; self.initialFocusIndex = index;
} }
}); });
return callback(null); return callback(null);
}, },
function populateList(callback) { function populateList(callback) {
const msgListView = vc.getView(MCICodesIDs.MsgList); const msgListView = vc.getView(MCICodesIDs.MsgList);
const listFormat = self.menuConfig.config.listFormat || '{msgNum} - {subject} - {toUserName}'; const listFormat = self.menuConfig.config.listFormat || '{msgNum} - {subject} - {toUserName}';
const focusListFormat = self.menuConfig.config.focusListFormat || listFormat; // :TODO: default change color here 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 // :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 // 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 => { msgListView.on('index update', idx => {
self.setViewText( self.setViewText(
'allViews', 'allViews',
MCICodesIDs.MsgInfo1, MCICodesIDs.MsgInfo1,
stringFormat(messageInfo1Format, { msgNumSelected : (idx + 1), msgNumTotal : self.messageList.length } )); stringFormat(messageInfo1Format, { msgNumSelected : (idx + 1), msgNumTotal : self.messageList.length } ));
}); });
if(self.initialFocusIndex > 0) { if(self.initialFocusIndex > 0) {
// note: causes redraw() // note: causes redraw()
msgListView.setFocusItemIndex(self.initialFocusIndex); msgListView.setFocusItemIndex(self.initialFocusIndex);
@ -228,29 +228,29 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
const messageInfo1Format = self.menuConfig.config.messageInfo1Format || '{msgNumSelected} / {msgNumTotal}'; const messageInfo1Format = self.menuConfig.config.messageInfo1Format || '{msgNumSelected} / {msgNumTotal}';
self.setViewText( self.setViewText(
'allViews', 'allViews',
MCICodesIDs.MsgInfo1, MCICodesIDs.MsgInfo1,
stringFormat(messageInfo1Format, { msgNumSelected : self.initialFocusIndex + 1, msgNumTotal : self.messageList.length } )); stringFormat(messageInfo1Format, { msgNumSelected : self.initialFocusIndex + 1, msgNumTotal : self.messageList.length } ));
return callback(null); return callback(null);
}, },
], ],
err => { err => {
if(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); return cb(err);
} }
); );
}); });
} }
getSaveState() { getSaveState() {
return { initialFocusIndex : this.initialFocusIndex }; return { initialFocusIndex : this.initialFocusIndex };
} }
restoreSavedState(savedState) { restoreSavedState(savedState) {
if(savedState) { if(savedState) {
this.initialFocusIndex = savedState.initialFocusIndex; this.initialFocusIndex = savedState.initialFocusIndex;
} }
} }
getMenuResult() { getMenuResult() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,9 @@ exports.readSAUCE = readSAUCE;
const SAUCE_SIZE = 128; const SAUCE_SIZE = 128;
const SAUCE_ID = new Buffer([0x53, 0x41, 0x55, 0x43, 0x45]); // 'SAUCE' 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; exports.SAUCE_SIZE = SAUCE_SIZE;
// :TODO: SAUCE should be a class // :TODO: SAUCE should be a class
@ -51,7 +53,7 @@ function readSAUCE(data, cb) {
if(!SAUCE_ID.equals(vars.id)) { if(!SAUCE_ID.equals(vars.id)) {
return cb(new Error('No SAUCE record present')); return cb(new Error('No SAUCE record present'));
} }
var ver = iconv.decode(vars.version, 'cp437'); 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', ['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; var codec = 'cp' + page;
SAUCE_FONT_TO_ENCODING_HINT['IBM EGA43 ' + page] = codec; SAUCE_FONT_TO_ENCODING_HINT['IBM EGA43 ' + page] = codec;
SAUCE_FONT_TO_ENCODING_HINT['IBM EGA ' + 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) => { User.getUserIdAndNameByLookup(lookupName, (err, localToUserId, localUserName) => {
if(err) { 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 // 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; const config = this.menuConfig.config;
this.target = config.target || 'message'; this.target = config.target || 'message';
this.scanDateFormat = config.scanDateFormat || 'YYYYMMDD'; this.scanDateFormat = config.scanDateFormat || 'YYYYMMDD';
this.menuMethods = { this.menuMethods = {
scanDateSubmit : (formData, extraArgs, cb) => { scanDateSubmit : (formData, extraArgs, cb) => {
@ -232,7 +232,7 @@ exports.getModule = class SetNewScanDate extends MenuModule {
const scanDateView = vc.getView(MciViewIds.main.scanDate); 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 // :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)); scanDateView.setText(today.format(scanDateFormat));
if('message' === self.target) { if('message' === self.target) {

View File

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

View File

@ -10,14 +10,14 @@ const moment = require('moment');
/* /*
System Event Log & Stats System Event Log & Stats
------------------------ ------------------------
System & user specific: System & user specific:
* Events for generating various statistics, logs such as last callers, etc. * Events for generating various statistics, logs such as last callers, etc.
* Stats such as counters * Stats such as counters
User specific stats are simply an alternate interface to user properties, while 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 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 { class StatLog {
constructor() { constructor() {
@ -66,7 +66,7 @@ class StatLog {
TimestampDesc : 'timestamp_desc', TimestampDesc : 'timestamp_desc',
Random : 'random', Random : 'random',
}; };
} }
setNonPeristentSystemStat(statName, statValue) { setNonPeristentSystemStat(statName, statValue) {
this.systemStats[statName] = statValue; this.systemStats[statName] = statValue;
@ -139,7 +139,7 @@ class StatLog {
return cb(new Error(`Value for ${statName} is not a number!`)); return cb(new Error(`Value for ${statName} is not a number!`));
} }
newValue += incrementBy; newValue += incrementBy;
} else { } else {
newValue = incrementBy; newValue = incrementBy;
} }
@ -201,19 +201,19 @@ class StatLog {
} }
} }
); );
break; break;
case 'forever' : case 'forever' :
default : default :
// nop // nop
break; break;
} }
} }
); );
} }
getSystemLogEntries(logName, order, limit, cb) { getSystemLogEntries(logName, order, limit, cb) {
let sql = let sql =
`SELECT timestamp, log_value `SELECT timestamp, log_value
FROM system_event_log FROM system_event_log
WHERE log_name = ?`; WHERE log_name = ?`;
@ -228,7 +228,7 @@ class StatLog {
sql += ' ORDER BY timestamp DESC'; sql += ' ORDER BY timestamp DESC';
break; break;
case 'random' : case 'random' :
sql += ' ORDER BY RANDOM()'; sql += ' ORDER BY RANDOM()';
} }
@ -279,7 +279,7 @@ class StatLog {
); );
} }
); );
} }
} }
module.exports = new 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 { const {
pad, pad,
stylizeString, stylizeString,
renderStringLength, renderStringLength,
renderSubstr, renderSubstr,
formatByteSize, formatByteSizeAbbr, formatByteSize, formatByteSizeAbbr,
@ -172,15 +172,15 @@ function formatNumberHelper(n, precision, type) {
case 'b' : return n.toString(2); case 'b' : return n.toString(2);
case 'o' : return n.toString(8); case 'o' : return n.toString(8);
case 'x' : return n.toString(16); case 'x' : return n.toString(16);
case 'e' : return n.toExponential(precision).replace(FormatNumRegExp.ExponentRep, '$&0'); case 'e' : return n.toExponential(precision).replace(FormatNumRegExp.ExponentRep, '$&0');
case 'f' : return n.toFixed(precision); case 'f' : return n.toFixed(precision);
case 'g' : case 'g' :
// we don't want useless trailing zeros. parseFloat -> back to string fixes this for us // we don't want useless trailing zeros. parseFloat -> back to string fixes this for us
return parseFloat(n.toPrecision(precision || 1)).toString(); return parseFloat(n.toPrecision(precision || 1)).toString();
case '%' : return formatNumberHelper(n * 100, precision, 'f') + '%'; case '%' : return formatNumberHelper(n * 100, precision, 'f') + '%';
case '' : return formatNumberHelper(n, precision, 'd'); case '' : return formatNumberHelper(n, precision, 'd');
default : default :
throw new ValueError(`Unknown format code "${type}" for object of type 'float'`); throw new ValueError(`Unknown format code "${type}" for object of type 'float'`);
} }
@ -207,7 +207,7 @@ function formatNumber(value, tokens) {
if('' !== tokens.precision) { if('' !== tokens.precision) {
throw new ValueError('Precision not allowed in integer format specifier'); throw new ValueError('Precision not allowed in integer format specifier');
} }
} else if( [ 'e', 'E', 'f', 'F', 'g', 'G', '%' ].indexOf(type) > - 1) { } else if( [ 'e', 'E', 'f', 'F', 'g', 'G', '%' ].indexOf(type) > - 1) {
if(tokens['#']) { if(tokens['#']) {
throw new ValueError('Alternate form (#) not allowed in float format specifier'); 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 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; '-' === tokens.sign ? '' : tokens.sign;
@ -223,7 +223,7 @@ function formatNumber(value, tokens) {
if(tokens[',']) { if(tokens[',']) {
const match = /^(\d*)(.*)$/.exec(s); const match = /^(\d*)(.*)$/.exec(s);
const separated = match[1].replace(/.(?=(...)+$)/g, '$&,') + match[2]; const separated = match[1].replace(/.(?=(...)+$)/g, '$&,') + match[2];
if('=' !== align) { if('=' !== align) {
return pad(sign + separated, width, fill, getPadAlign(align)); return pad(sign + separated, width, fill, getPadAlign(align));
@ -246,7 +246,7 @@ function formatNumber(value, tokens) {
if(0 === width) { if(0 === width) {
return sign + prefix + s; return sign + prefix + s;
} }
if('=' === align) { if('=' === align) {
return sign + prefix + pad(s, width - sign.length - prefix.length, fill, getPadAlign('>')); return sign + prefix + pad(s, width - sign.length - prefix.length, fill, getPadAlign('>'));
@ -272,9 +272,9 @@ const transformers = {
styleL33t : (s) => stylizeString(s, 'l33t'), styleL33t : (s) => stylizeString(s, 'l33t'),
// :TODO: // :TODO:
// toMegs(), toKilobytes(), ... // toMegs(), toKilobytes(), ...
// toList(), toCommaList(), // toList(), toCommaList(),
sizeWithAbbr : (n) => formatByteSize(n, true, 2), sizeWithAbbr : (n) => formatByteSize(n, true, 2),
sizeWithoutAbbr : (n) => formatByteSize(n, false, 2), sizeWithoutAbbr : (n) => formatByteSize(n, false, 2),
sizeAbbr : (n) => formatByteSizeAbbr(n), 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. // :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) { function getValue(obj, path) {
const value = _.get(obj, path); const value = _.get(obj, path);
if(!_.isUndefined(value)) { if(!_.isUndefined(value)) {
return _.isFunction(value) ? value() : value; return _.isFunction(value) ? value() : value;
} }
throw new KeyError(quote(path)); throw new KeyError(quote(path));
} }
@ -350,7 +350,7 @@ module.exports = function format(fmt, obj) {
// remainder // remainder
if(pos < fmt.length) { if(pos < fmt.length) {
out += fmt.slice(pos); out += fmt.slice(pos);
} }
return out; return out;
}; };

View File

@ -3,7 +3,6 @@
// ENiGMA½ // ENiGMA½
const miscUtil = require('./misc_util.js'); const miscUtil = require('./misc_util.js');
const ANSIEscapeParser = require('./ansi_escape_parser.js').ANSIEscapeParser;
const ANSI = require('./ansi_term.js'); const ANSI = require('./ansi_term.js');
// deps // deps
@ -53,12 +52,12 @@ function stylizeString(s, style) {
switch(style) { switch(style) {
// None/normal // None/normal
case 'normal' : case 'normal' :
case 'N' : case 'N' :
return s; return s;
// UPPERCASE // UPPERCASE
case 'upper' : case 'upper' :
case 'U' : case 'U' :
return s.toUpperCase(); return s.toUpperCase();
// lowercase // lowercase
@ -107,8 +106,8 @@ function stylizeString(s, style) {
return stylized; return stylized;
// Small i's: DEMENTiA // Small i's: DEMENTiA
case 'small i' : case 'small i' :
case 'i' : case 'i' :
return s.toUpperCase().replace(/I/g, 'i'); return s.toUpperCase().replace(/I/g, 'i');
// mIxeD CaSE (random upper/lower) // mIxeD CaSE (random upper/lower)
@ -128,7 +127,7 @@ function stylizeString(s, style) {
case '3' : case '3' :
for(i = 0; i < len; ++i) { for(i = 0; i < len; ++i) {
c = SIMPLE_ELITE_MAP[s[i].toLowerCase()]; c = SIMPLE_ELITE_MAP[s[i].toLowerCase()];
stylized += c || s[i]; stylized += c || s[i];
} }
return stylized; return stylized;
} }
@ -147,11 +146,11 @@ function pad(s, len, padChar, dir, stringSGR, padSGR, useRenderLen) {
useRenderLen = miscUtil.valueWithDefault(useRenderLen, true); useRenderLen = miscUtil.valueWithDefault(useRenderLen, true);
const renderLen = useRenderLen ? renderStringLength(s) : s.length; const renderLen = useRenderLen ? renderStringLength(s) : s.length;
const padlen = len >= renderLen ? len - renderLen : 0; const padlen = len >= renderLen ? len - renderLen : 0;
switch(dir) { switch(dir) {
case 'L' : case 'L' :
case 'left' : case 'left' :
s = padSGR + new Array(padlen).join(padChar) + stringSGR + s; s = padSGR + new Array(padlen).join(padChar) + stringSGR + s;
break; break;
@ -162,10 +161,10 @@ function pad(s, len, padChar, dir, stringSGR, padSGR, useRenderLen) {
const right = Math.ceil(padlen / 2); const right = Math.ceil(padlen / 2);
const left = padlen - right; const left = padlen - right;
s = padSGR + new Array(left + 1).join(padChar) + stringSGR + s + padSGR + new Array(right + 1).join(padChar); s = padSGR + new Array(left + 1).join(padChar) + stringSGR + s + padSGR + new Array(right + 1).join(padChar);
} }
break; break;
case 'R' : case 'R' :
case 'right' : case 'right' :
s = stringSGR + s + padSGR + new Array(padlen).join(padChar); s = stringSGR + s + padSGR + new Array(padlen).join(padChar);
break; break;
@ -184,7 +183,7 @@ function replaceAt(s, n, t) {
return s.substring(0, n) + t + s.substring(n + 1); 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 /[\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) { function isPrintable(s) {
@ -198,11 +197,6 @@ function isPrintable(s) {
return !RE_NON_PRINTABLE.test(s); return !RE_NON_PRINTABLE.test(s);
} }
function stringLength(s) {
// :TODO: See https://mathiasbynens.be/notes/javascript-unicode
return s.length;
}
function stripAllLineFeeds(s) { function stripAllLineFeeds(s) {
return s.replace(/\r?\n|[\r\u2028\u2029]/g, ''); return s.replace(/\r?\n|[\r\u2028\u2029]/g, '');
} }
@ -256,7 +250,7 @@ function renderSubstr(str, start, length) {
match = re.exec(str); match = re.exec(str);
if(match) { if(match) {
if(match.index > pos) { if(match.index > pos) {
s = str.slice(pos + start, Math.min(match.index, pos + (length - renderLen))); s = str.slice(pos + start, Math.min(match.index, pos + (length - renderLen)));
start = 0; // start offset applies only once start = 0; // start offset applies only once
out += s; out += s;
@ -269,7 +263,7 @@ function renderSubstr(str, start, length) {
// remainder // remainder
if(pos + start < str.length && renderLen < length) { 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))); //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 // We additionally account for ANSI *forward* movement ESC sequences
// in the form of ESC[<N>C where <N> is the "go forward" character count. // 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; const re = ANSI_OR_PIPE_REGEXP;
re.lastIndex = 0; // we recycle the rege; reset re.lastIndex = 0; // we recycle the rege; reset
// //
// Loop counting only literal (non-control) sequences // Loop counting only literal (non-control) sequences
// paying special attention to ESC[<N>C which means forward <N> // paying special attention to ESC[<N>C which means forward <N>
// //
do { do {
pos = re.lastIndex; pos = re.lastIndex;
m = re.exec(s); m = re.exec(s);
if(m) { if(m) {
if(m.index > pos) { if(m.index > pos) {
len += s.slice(pos, m.index).length; len += s.slice(pos, m.index).length;
} }
if('C' === m[3]) { // ESC[<N>C is foward/right if('C' === m[3]) { // ESC[<N>C is foward/right
len += parseInt(m[2], 10) || 0; len += parseInt(m[2], 10) || 0;
} }
} }
} while(0 !== re.lastIndex); } while(0 !== re.lastIndex);
if(pos < s.length) { if(pos < s.length) {
len += s.slice(pos).length; len += s.slice(pos).length;
} }
return len; 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) { function formatByteSizeAbbr(byteSize) {
if(0 === byteSize) { if(0 === byteSize) {
return BYTE_SIZE_ABBRS[0]; // B return BYTE_SIZE_ABBRS[0]; // B
} }
return BYTE_SIZE_ABBRS[Math.floor(Math.log(byteSize) / Math.log(1024))]; 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)); const i = 0 === byteSize ? byteSize : Math.floor(Math.log(byteSize) / Math.log(1024));
let result = parseFloat((byteSize / Math.pow(1024, i)).toFixed(decimals)); let result = parseFloat((byteSize / Math.pow(1024, i)).toFixed(decimals));
if(withAbbr) { if(withAbbr) {
result += ` ${BYTE_SIZE_ABBRS[i]}`; result += ` ${BYTE_SIZE_ABBRS[i]}`;
} }
return result; 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)); const i = 0 === count ? count : Math.floor(Math.log(count) / Math.log(1000));
let result = parseFloat((count / Math.pow(1000, i)).toFixed(decimals)); let result = parseFloat((count / Math.pow(1000, i)).toFixed(decimals));
if(withAbbr) { if(withAbbr) {
result += `${COUNT_ABBRS[i]}`; result += `${COUNT_ABBRS[i]}`;
} }
return result; 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 // :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]*?)([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 = [ const ANSI_OPCODES_ALLOWED_CLEAN = [
//'A', 'B', // up, down //'A', 'B', // up, down
//'C', 'D', // right, left //'C', 'D', // right, left
@ -370,17 +364,17 @@ function cleanControlCodes(input, options) {
let m; let m;
let pos; let pos;
let cleaned = ''; let cleaned = '';
options = options || {}; options = options || {};
// //
// Loop through |input| adding only allowed ESC // Loop through |input| adding only allowed ESC
// sequences and literals to |cleaned| // sequences and literals to |cleaned|
// //
do { do {
pos = REGEXP_ANSI_CONTROL_CODES.lastIndex; pos = REGEXP_ANSI_CONTROL_CODES.lastIndex;
m = REGEXP_ANSI_CONTROL_CODES.exec(input); m = REGEXP_ANSI_CONTROL_CODES.exec(input);
if(m) { if(m) {
if(m.index > pos) { if(m.index > pos) {
cleaned += input.slice(pos, m.index); cleaned += input.slice(pos, m.index);
@ -394,205 +388,17 @@ function cleanControlCodes(input, options) {
cleaned += m[0]; cleaned += m[0];
} }
} }
} while(0 !== REGEXP_ANSI_CONTROL_CODES.lastIndex); } while(0 !== REGEXP_ANSI_CONTROL_CODES.lastIndex);
// remainder // remainder
if(pos < input.length) { if(pos < input.length) {
cleaned += input.slice(pos); cleaned += input.slice(pos);
} }
return cleaned; 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) { function isAnsiLine(line) {
return isAnsi(line);// || renderStringLength(line) < line.length; return isAnsi(line);// || renderStringLength(line) < line.length;
} }
@ -622,22 +428,23 @@ function isFormattedLine(line) {
return false; return false;
} }
// :TODO: rename to containsAnsi()
function isAnsi(input) { function isAnsi(input) {
if(!input || 0 === input.length) { if(!input || 0 === input.length) {
return false; return false;
} }
// //
// * ANSI found - limited, just colors // * ANSI found - limited, just colors
// * Full ANSI art // * Full ANSI art
// * // *
// //
// FULL ANSI art: // FULL ANSI art:
// * SAUCE present & reports as ANSI art // * SAUCE present & reports as ANSI art
// * ANSI clear screen within first 2-3 codes // * ANSI clear screen within first 2-3 codes
// * ANSI movement codes (goto, right, left, etc.) // * ANSI movement codes (goto, right, left, etc.)
// //
// * // *
/* /*
readSAUCE(input, (err, sauce) => { readSAUCE(input, (err, sauce) => {
if(!err && ('ANSi' === sauce.fileType || 'ANSiMation' === sauce.fileType)) { 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 // :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 ANSI_DET_REGEXP = /(?:\x1b\x5b)[?=;0-9]*?[ABCDEFGHJKLMSTfhlmnprsu]/g; // eslint-disable-line no-control-regex
const m = input.match(ANSI_DET_REGEXP) || []; const m = input.match(ANSI_DET_REGEXP) || [];
return m.length >= 4; // :TODO: do this reasonably, e.g. a percent or soemthing 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); return callingMenu.prevMenu(cb);
} }
} }
// success! // success!
return callingMenu.nextMenu(cb); return callingMenu.nextMenu(cb);
}); });
@ -72,7 +72,7 @@ function prevMenu(callingMenu, formData, extraArgs, cb) {
callingMenu.prevMenu( err => { callingMenu.prevMenu( err => {
if(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); return cb(err);
}); });
@ -119,7 +119,7 @@ function nextConf(callingMenu, formData, extraArgs, cb) {
if(err) { if(err) {
return cb(err); // logged within changeMessageConference() return cb(err); // logged within changeMessageConference()
} }
return reloadMenu(callingMenu, cb); return reloadMenu(callingMenu, cb);
}); });
} }
@ -132,7 +132,7 @@ function prevArea(callingMenu, formData, extraArgs, cb) {
if(err) { if(err) {
return cb(err); // logged within changeMessageArea() return cb(err); // logged within changeMessageArea()
} }
return reloadMenu(callingMenu, cb); return reloadMenu(callingMenu, cb);
}); });
} }
@ -155,10 +155,10 @@ function nextArea(callingMenu, formData, extraArgs, cb) {
} }
function sendForgotPasswordEmail(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; const WebPasswordReset = require('./web_password_reset.js').WebPasswordReset;
WebPasswordReset.sendForgotPasswordEmail(username, err => { WebPasswordReset.sendForgotPasswordEmail(username, err => {
if(err) { if(err) {
callingMenu.client.log.warn( { err : err.message }, 'Failed sending forgot password email'); 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) { if(extraArgs.next) {
return callingMenu.gotoMenu(extraArgs.next, cb); 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) { function validateEmailAvail(data, cb) {
// //
// This particular method allows empty data - e.g. no email entered // This particular method allows empty data - e.g. no email entered
// //
if(!data || 0 === data.length) { if(!data || 0 === data.length) {
return cb(null); 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 // 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)) { if(!emailRegExp.test(data)) {
return cb(new Error('Invalid email address')); return cb(new Error('Invalid email address'));
} }
@ -121,8 +121,8 @@ function validateEmailAvail(data, cb) {
} else if(uids.length > 0) { } else if(uids.length > 0) {
return cb(new Error('Email address not unique')); 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; this.client = client;
} }
restorePipe() { restorePipe() {
if(!this.pipeRestored) { if(!this.pipeRestored) {
this.pipeRestored = true; this.pipeRestored = true;
@ -68,14 +68,14 @@ class TelnetClientConnection extends EventEmitter {
this.bridgeConnection.on('data', data => { this.bridgeConnection.on('data', data => {
this.client.term.rawWrite(data); this.client.term.rawWrite(data);
// //
// Wait for a terminal type request, and send it eactly once. // Wait for a terminal type request, and send it eactly once.
// This is enough (in additional to other negotiations handled in telnet.js) // This is enough (in additional to other negotiations handled in telnet.js)
// to get us in on most systems // to get us in on most systems
// //
if(!this.termSent && data.indexOf(IAC_DO_TERM_TYPE) > -1) { if(!this.termSent && data.indexOf(IAC_DO_TERM_TYPE) > -1) {
this.termSent = true; 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. // actual/current terminal type.
// //
let bufs = buffers(); let bufs = buffers();
bufs.push(new Buffer( bufs.push(new Buffer(
[ [
255, // IAC 255, // IAC
250, // SB 250, // SB
24, // TERMINAL-TYPE 24, // TERMINAL-TYPE
@ -113,9 +113,9 @@ class TelnetClientConnection extends EventEmitter {
)); ));
bufs.push( 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 new Buffer( [ 255, 240 ] ) // IAC, SE
); );
return bufs.toBuffer(); return bufs.toBuffer();
} }
@ -128,9 +128,9 @@ exports.getModule = class TelnetBridgeModule extends MenuModule {
this.config = options.menuConfig.config; this.config = options.menuConfig.config;
// defaults // defaults
this.config.port = this.config.port || 23; this.config.port = this.config.port || 23;
} }
initSequence() { initSequence() {
let clientTerminated; let clientTerminated;
const self = this; const self = this;
@ -158,7 +158,7 @@ exports.getModule = class TelnetBridgeModule extends MenuModule {
self.client.term.write(` Connecting to ${connectOpts.host}, please wait...\n`); self.client.term.write(` Connecting to ${connectOpts.host}, please wait...\n`);
const telnetConnection = new TelnetClientConnection(self.client); const telnetConnection = new TelnetClientConnection(self.client);
telnetConnection.on('connected', () => { telnetConnection.on('connected', () => {
self.client.log.info(connectOpts, 'Telnet bridge connection established'); self.client.log.info(connectOpts, 'Telnet bridge connection established');

View File

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

View File

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

View File

@ -28,7 +28,7 @@ module.exports = class TicFileInfo {
static get requiredFields() { static get requiredFields() {
return [ return [
'Area', 'Origin', 'From', 'File', 'Crc', 'Area', 'Origin', 'From', 'File', 'Crc',
// :TODO: validate this: // :TODO: validate this:
//'Path', 'Seenby' // these two are questionable; some systems don't send them? //'Path', 'Seenby' // these two are questionable; some systems don't send them?
]; ];
@ -43,16 +43,16 @@ module.exports = class TicFileInfo {
if(value) { if(value) {
// //
// We call toString() on values to ensure numbers, addresses, etc. are converted // We call toString() on values to ensure numbers, addresses, etc. are converted
// //
joinWith = joinWith || ''; joinWith = joinWith || '';
if(Array.isArray(value)) { if(Array.isArray(value)) {
return value.map(v => v.toString() ).join(joinWith); return value.map(v => v.toString() ).join(joinWith);
} }
return value.toString(); return value.toString();
} }
} }
get filePath() { get filePath() {
return paths.join(paths.dirname(this.path), this.getAsString('File')); return paths.join(paths.dirname(this.path), this.getAsString('File'));
} }
@ -86,7 +86,7 @@ module.exports = class TicFileInfo {
const localInfo = { const localInfo = {
areaTag : config.localAreaTags.find( areaTag => areaTag.toUpperCase() === area ), areaTag : config.localAreaTags.find( areaTag => areaTag.toUpperCase() === area ),
}; };
if(!localInfo.areaTag) { if(!localInfo.areaTag) {
return callback(Errors.Invalid(`No local area for "Area" of ${area}`)); return callback(Errors.Invalid(`No local area for "Area" of ${area}`));
} }
@ -112,7 +112,7 @@ module.exports = class TicFileInfo {
return callback(null, localInfo); return callback(null, localInfo);
}, },
function checksumAndSize(localInfo, callback) { function checksumAndSize(localInfo, callback) {
const crcTic = self.get('Crc'); const crcTic = self.get('Crc');
const stream = fs.createReadStream(self.filePath); const stream = fs.createReadStream(self.filePath);
const crc = new CRC32(); const crc = new CRC32();
let sizeActual = 0; let sizeActual = 0;
@ -193,7 +193,7 @@ module.exports = class TicFileInfo {
// This is an optional keyword." // This is an optional keyword."
// //
const to = this.get('To'); const to = this.get('To');
if(!to) { if(!to) {
return allowNonExplicit; return allowNonExplicit;
} }
@ -219,10 +219,10 @@ module.exports = class TicFileInfo {
let key; let key;
let value; let value;
let entry; let entry;
lines.forEach(line => { lines.forEach(line => {
keyEnd = line.search(/\s/); keyEnd = line.search(/\s/);
if(keyEnd < 0) { if(keyEnd < 0) {
keyEnd = line.length; keyEnd = line.length;
} }
@ -253,7 +253,7 @@ module.exports = class TicFileInfo {
value = parseInt(value, 16); value = parseInt(value, 16);
break; break;
case 'size' : case 'size' :
value = parseInt(value, 10); value = parseInt(value, 10);
break; 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 */ /* jslint node: true */
'use strict'; 'use strict';
var MenuView = require('./menu_view.js').MenuView; const MenuView = require('./menu_view.js').MenuView;
var ansi = require('./ansi_term.js'); const strUtil = require('./string_util.js');
var strUtil = require('./string_util.js');
var util = require('util'); const util = require('util');
var assert = require('assert'); const assert = require('assert');
var _ = require('lodash');
exports.ToggleMenuView = ToggleMenuView; exports.ToggleMenuView = ToggleMenuView;
@ -44,7 +42,7 @@ ToggleMenuView.prototype.redraw = function() {
var item = this.items[i]; var item = this.items[i];
var text = strUtil.stylizeString( var text = strUtil.stylizeString(
item.text, i === this.focusedItemIndex && this.hasFocus ? this.focusTextStyle : this.textStyle); item.text, i === this.focusedItemIndex && this.hasFocus ? this.focusTextStyle : this.textStyle);
if(1 === i) { if(1 === i) {
//console.log(this.styleColor1) //console.log(this.styleColor1)
//var sepColor = this.getANSIColor(this.styleColor1 || this.getColor()); //var sepColor = this.getANSIColor(this.styleColor1 || this.getColor());

View File

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

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