From ac1433e84beda36d89044e7f889b317bf21771ad Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Mon, 15 Jan 2018 12:22:11 -0700 Subject: [PATCH] * Code cleanup and eslint since -- remove unused variables, clean up RegExs, so on... --- core/abracadabra.js | 10 +- core/acs.js | 4 +- core/ansi_escape_parser.js | 56 +++-- core/ansi_prep.js | 22 +- core/ansi_term.js | 82 ++++---- core/archive_util.js | 44 ++-- core/art.js | 16 +- core/asset.js | 8 +- core/bbs.js | 2 +- core/bbs_link.js | 10 +- core/bbs_list.js | 16 +- core/button_view.js | 2 +- core/client.js | 46 ++--- core/client_connections.js | 2 +- core/client_term.js | 14 +- core/color_codes.js | 10 +- core/combatnet.js | 92 ++++----- core/conf_area_util.js | 2 +- core/config.js | 4 +- core/config_cache.js | 2 +- core/connect.js | 2 +- core/crc.js | 4 +- core/database.js | 12 +- core/door.js | 10 +- core/door_party.js | 42 ++-- core/download_queue.js | 6 +- core/edit_text_view.js | 4 +- core/enig_error.js | 2 +- core/enigma_assert.js | 4 +- core/erc_client.js | 16 +- core/event_scheduler.js | 82 ++++---- core/exodus.js | 4 +- core/file_area_filter_edit.js | 28 +-- core/file_area_list.js | 54 ++--- core/file_area_web.js | 12 +- core/file_base_area.js | 70 +++---- core/file_base_area_select.js | 2 +- core/file_base_download_manager.js | 8 +- core/file_base_filter.js | 16 +- core/file_base_search.js | 2 +- core/file_base_web_download_manager.js | 27 ++- core/file_entry.js | 24 +-- core/file_transfer.js | 40 ++-- core/file_transfer_protocol_select.js | 4 +- core/file_util.js | 4 +- core/fnv1a.js | 10 +- core/fse.js | 134 ++++++------ core/ftn_address.js | 8 +- core/ftn_mail_packet.js | 146 ++++++------- core/ftn_util.js | 62 +++--- core/horizontal_menu_view.js | 4 +- core/key_entry_view.js | 4 +- core/last_callers.js | 12 +- core/logger.js | 8 +- core/login_server_module.js | 8 +- core/mail_packet.js | 2 +- core/mail_util.js | 2 +- core/mask_edit_text_view.js | 16 +- core/mci_view_factory.js | 25 ++- core/menu_module.js | 32 +-- core/menu_stack.js | 10 +- core/menu_util.js | 44 ++-- core/menu_view.js | 14 +- core/message.js | 112 +++++----- core/message_area.js | 98 ++++----- core/mime_util.js | 2 +- core/misc_util.js | 4 +- core/mod_mixins.js | 6 +- core/msg_area_list.js | 20 +- core/msg_area_post_fse.js | 4 +- core/msg_area_view_fse.js | 8 +- core/msg_conf_list.js | 18 +- core/msg_list.js | 38 ++-- core/msg_network.js | 8 +- core/msg_scan_toss_module.js | 6 +- core/multi_line_edit_text_view.js | 29 ++- core/new_scan.js | 42 ++-- core/nua.js | 16 +- core/onelinerz.js | 26 +-- core/plugin_module.js | 2 +- core/predefined_mci.js | 8 +- core/rumorz.js | 18 +- core/sauce.js | 8 +- core/scanner_tossers/ftn_bso.js | 25 ++- core/set_newscan_date.js | 4 +- core/spinner_menu_view.js | 23 +-- core/stat_log.js | 18 +- core/stats.js | 30 --- core/status_bar_view.js | 64 ------ core/string_format.js | 30 +-- core/string_util.js | 275 ++++--------------------- core/system_menu_method.js | 18 +- core/system_view_validate.js | 8 +- core/telnet_bridge.js | 20 +- core/text_view.js | 50 ++--- core/theme.js | 140 ++++++------- core/tic_file_info.js | 20 +- core/ticker_text_view.js | 94 --------- core/toggle_menu_view.js | 12 +- core/upload.js | 52 ++--- core/user.js | 40 ++-- core/user_config.js | 46 ++--- core/user_group.js | 54 +++-- core/user_list.js | 6 +- core/user_login.js | 8 +- core/uuid_util.js | 10 +- core/vertical_menu_view.js | 16 +- core/view.js | 16 +- core/view_controller.js | 70 +++---- core/web_password_reset.js | 19 +- core/whos_online.js | 2 +- core/word_wrap.js | 166 +++------------ 112 files changed, 1375 insertions(+), 1898 deletions(-) delete mode 100644 core/stats.js delete mode 100644 core/status_bar_view.js delete mode 100644 core/ticker_text_view.js diff --git a/core/abracadabra.js b/core/abracadabra.js index 85d1e205..0ac17887 100644 --- a/core/abracadabra.js +++ b/core/abracadabra.js @@ -87,11 +87,11 @@ exports.getModule = class AbracadabraModule extends MenuModule { [ function validateNodeCount(callback) { if(self.config.nodeMax > 0 && - _.isNumber(activeDoorNodeInstances[self.config.name]) && + _.isNumber(activeDoorNodeInstances[self.config.name]) && activeDoorNodeInstances[self.config.name] + 1 > self.config.nodeMax) { - self.client.log.info( - { + self.client.log.info( + { name : self.config.name, activeCount : activeDoorNodeInstances[self.config.name] }, @@ -118,11 +118,11 @@ exports.getModule = class AbracadabraModule extends MenuModule { } else { activeDoorNodeInstances[self.config.name] = 1; } - + callback(null); } }, - function generateDropfile(callback) { + function generateDropfile(callback) { self.dropFile = new DropFile(self.client, self.config.dropFileType); var fullPath = self.dropFile.fullPath; diff --git a/core/acs.js b/core/acs.js index f2e04b9f..9532ad78 100644 --- a/core/acs.js +++ b/core/acs.js @@ -13,7 +13,7 @@ class ACS { constructor(client) { this.client = client; } - + check(acs, scope, defaultAcs) { acs = acs ? acs[scope] : defaultAcs; acs = acs || defaultAcs; @@ -22,7 +22,7 @@ class ACS { } catch(e) { Log.warn( { exception : e, acs : acs }, 'Exception caught checking ACS'); return false; - } + } } // diff --git a/core/ansi_escape_parser.js b/core/ansi_escape_parser.js index 7e777618..feb7b164 100644 --- a/core/ansi_escape_parser.js +++ b/core/ansi_escape_parser.js @@ -3,7 +3,9 @@ const miscUtil = require('./misc_util.js'); const ansi = require('./ansi_term.js'); +const Log = require('./logger.js').log; +// deps const events = require('events'); const util = require('util'); const _ = require('lodash'); @@ -24,7 +26,7 @@ function ANSIEscapeParser(options) { this.graphicRendition = {}; this.parseState = { - re : /(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g, + re : /(?:\x1b\x5b)([?=;0-9]*?)([ABCDHJKfhlmnpsu])/g, // eslint-disable-line no-control-regex }; options = miscUtil.valueWithDefault(options, { @@ -46,7 +48,7 @@ function ANSIEscapeParser(options) { self.column = Math.max(self.column, 1); self.column = Math.min(self.column, self.termWidth); // can't move past term width self.row = Math.max(self.row, 1); - + self.positionUpdated(); }; @@ -63,7 +65,7 @@ function ANSIEscapeParser(options) { delete self.savedPosition; self.positionUpdated(); -// self.rowUpdated(); + // self.rowUpdated(); }; self.clearScreen = function() { @@ -71,7 +73,7 @@ function ANSIEscapeParser(options) { self.emit('clear screen'); }; -/* + /* self.rowUpdated = function() { self.emit('row update', self.row + self.scrollBack); };*/ @@ -95,7 +97,7 @@ function ANSIEscapeParser(options) { start = pos; self.column = 1; - + self.positionUpdated(); break; @@ -132,7 +134,7 @@ function ANSIEscapeParser(options) { if(self.column > self.termWidth) { self.column = 1; self.row += 1; - + self.positionUpdated(); } @@ -142,17 +144,9 @@ function ANSIEscapeParser(options) { } } - function getProcessedMCI(mci) { - if(self.mciReplaceChar.length > 0) { - return ansi.getSGRFromGraphicRendition(self.graphicRendition, true) + new Array(mci.length + 1).join(self.mciReplaceChar); - } else { - return mci; - } - } - function parseMCI(buffer) { // :TODO: move this to "constants" seciton @ top - var mciRe = /\%([A-Z]{2})([0-9]{1,2})?(?:\(([0-9A-Za-z,]+)\))*/g; + var mciRe = /%([A-Z]{2})([0-9]{1,2})?(?:\(([0-9A-Za-z,]+)\))*/g; var pos = 0; var match; var mciCode; @@ -186,27 +180,23 @@ function ANSIEscapeParser(options) { self.graphicRenditionForErase = _.clone(self.graphicRendition); } - - self.emit('mci', { - mci : mciCode, + + self.emit('mci', { + mci : mciCode, id : id ? parseInt(id, 10) : null, - args : args, + args : args, SGR : ansi.getSGRFromGraphicRendition(self.graphicRendition, true) }); if(self.mciReplaceChar.length > 0) { const sgrCtrl = ansi.getSGRFromGraphicRendition(self.graphicRenditionForErase); - - self.emit('control', sgrCtrl, 'm', sgrCtrl.slice(2).split(/[\;m]/).slice(0, 3)); + + self.emit('control', sgrCtrl, 'm', sgrCtrl.slice(2).split(/[;m]/).slice(0, 3)); literal(new Array(match[0].length + 1).join(self.mciReplaceChar)); } else { literal(match[0]); } - - //literal(getProcessedMCI(match[0])); - - //self.emit('chunk', getProcessedMCI(match[0])); } } while(0 !== mciRe.lastIndex); @@ -220,7 +210,7 @@ function ANSIEscapeParser(options) { self.parseState = { // ignore anything past EOF marker, if any buffer : input.split(String.fromCharCode(0x1a), 1)[0], - re : /(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g, + re : /(?:\x1b\x5b)([?=;0-9]*?)([ABCDHJKfhlmnpsu])/g, // eslint-disable-line no-control-regex stop : false, }; }; @@ -290,14 +280,14 @@ function ANSIEscapeParser(options) { break; } } - - parseMCI(lastBit) + + parseMCI(lastBit); } self.emit('complete'); }; -/* + /* self.parse = function(buffer, savedRe) { // :TODO: ensure this conforms to ANSI-BBS / CTerm / bansi.txt for movement/etc. // :TODO: move this to "constants" section @ top @@ -382,12 +372,12 @@ function ANSIEscapeParser(options) { break; // save position - case 's' : + case 's' : self.saveCursorPosition(); break; // restore position - case 'u' : + case 'u' : self.restoreCursorPosition(); break; @@ -422,7 +412,7 @@ function ANSIEscapeParser(options) { case 1 : case 2 : - case 22 : + case 22 : self.graphicRendition.intensity = arg; break; @@ -448,7 +438,7 @@ function ANSIEscapeParser(options) { break; default : - console.log('Unknown attribute: ' + arg); // :TODO: Log properly + Log.trace( { attribute : arg }, 'Unknown attribute while parsing ANSI'); break; } } diff --git a/core/ansi_prep.js b/core/ansi_prep.js index 45b93d32..a4c894d8 100644 --- a/core/ansi_prep.js +++ b/core/ansi_prep.js @@ -4,7 +4,7 @@ // ENiGMA½ const ANSIEscapeParser = require('./ansi_escape_parser.js').ANSIEscapeParser; const ANSI = require('./ansi_term.js'); -const { +const { splitTextAtTerms, renderStringLength } = require('./string_util.js'); @@ -41,7 +41,7 @@ module.exports = function ansiPrep(input, options, cb) { if(canvas[row]) { return; } - + canvas[row] = Array.from( { length : options.cols}, () => new Object() ); } @@ -113,17 +113,17 @@ module.exports = function ansiPrep(input, options, cb) { const lastCol = getLastPopulatedColumn(row) + 1; let i; - line = options.indent ? + line = options.indent ? output.length > 0 ? ' '.repeat(options.indent) : '' : ''; - + for(i = 0; i < lastCol; ++i) { const col = row[i]; - sgr = !options.asciiMode && 0 === i ? + sgr = !options.asciiMode && 0 === i ? col.initialSgr ? ANSI.getSGRFromGraphicRendition(col.initialSgr) : '' : ''; - + if(!options.asciiMode && col.sgr) { sgr += ANSI.getSGRFromGraphicRendition(col.sgr); } @@ -148,7 +148,7 @@ module.exports = function ansiPrep(input, options, cb) { if(options.exportMode) { // // If we're in export mode, we do some additional hackery: - // + // // * Hard wrap ALL lines at <= 79 *characters* (not visible columns) // if a line must wrap early, we'll place a ESC[A ESC[C where // represents chars to get back to the position we were previously at @@ -157,8 +157,8 @@ module.exports = function ansiPrep(input, options, cb) { // // :TODO: this would be better to do as part of the processing above, but this will do for now const MAX_CHARS = 79 - 8; // 79 max, - 8 for max ESC seq's we may prefix a line with - let exportOutput = ''; - + let exportOutput = ''; + let m; let afterSeq; let wantMore; @@ -184,7 +184,7 @@ module.exports = function ansiPrep(input, options, cb) { splitAt = m.index; wantMore = false; // can't eat up any more } - + break; // seq's beyond this point are >= MAX_CHARS } } @@ -203,7 +203,7 @@ module.exports = function ansiPrep(input, options, cb) { exportOutput += `${part}\r\n`; if(fullLine.length > 0) { // more to go for this line? - exportOutput += `${ANSI.up()}${ANSI.right(renderStart)}`; + exportOutput += `${ANSI.up()}${ANSI.right(renderStart)}`; } else { exportOutput += ANSI.up(); } diff --git a/core/ansi_term.js b/core/ansi_term.js index 7eb10ec2..0a1eaa41 100644 --- a/core/ansi_term.js +++ b/core/ansi_term.js @@ -3,7 +3,7 @@ // // ANSI Terminal Support Resources -// +// // ANSI-BBS // * http://ansi-bbs.org/ // @@ -31,7 +31,7 @@ // For a board, we need to support the semi-standard ANSI-BBS "spec" which // is bastardized mix of DOS ANSI.SYS, cterm.txt, bansi.txt and a little other. // This gives us NetRunner, SyncTERM, EtherTerm, most *nix terminals, compatibilitiy -// with legit oldschool DOS terminals, and so on. +// with legit oldschool DOS terminals, and so on. // // ENiGMA½ @@ -113,7 +113,7 @@ const CONTROL = { // // Support: // * SyncTERM: Works as expected - // * NetRunner: + // * NetRunner: // // General Notes: // See also notes in bansi.txt and cterm.txt about the various @@ -160,7 +160,7 @@ const SGRValues = { negative : 7, hidden : 8, - normal : 22, // + normal : 22, // steady : 25, positive : 27, @@ -203,7 +203,7 @@ function getBGColorValue(name) { // :TODO: Create mappings for aliases... maybe make this a map to values instead // :TODO: Break this up in to two parts: // 1) FONT_AND_CODE_PAGES (e.g. SyncTERM/cterm) -// 2) SAUCE_FONT_MAP: Sauce name(s) -> items in FONT_AND_CODE_PAGES. +// 2) SAUCE_FONT_MAP: Sauce name(s) -> items in FONT_AND_CODE_PAGES. // ...we can then have getFontFromSAUCEName(sauceFontName) // Also, create a SAUCE_ENCODING_MAP: SAUCE font name -> encodings @@ -215,45 +215,45 @@ function getBGColorValue(name) { // const SYNCTERM_FONT_AND_ENCODING_TABLE = [ 'cp437', - 'cp1251', - 'koi8_r', - 'iso8859_2', - 'iso8859_4', - 'cp866', - 'iso8859_9', - 'haik8', - 'iso8859_8', - 'koi8_u', - 'iso8859_15', + 'cp1251', + 'koi8_r', + 'iso8859_2', 'iso8859_4', - 'koi8_r_b', - 'iso8859_4', - 'iso8859_5', - 'ARMSCII_8', + 'cp866', + 'iso8859_9', + 'haik8', + 'iso8859_8', + 'koi8_u', 'iso8859_15', - 'cp850', - 'cp850', - 'cp885', - 'cp1251', - 'iso8859_7', - 'koi8-r_c', - 'iso8859_4', - 'iso8859_1', - 'cp866', - 'cp437', - 'cp866', + 'iso8859_4', + 'koi8_r_b', + 'iso8859_4', + 'iso8859_5', + 'ARMSCII_8', + 'iso8859_15', + 'cp850', + 'cp850', 'cp885', - 'cp866_u', - 'iso8859_1', - 'cp1131', - 'c64_upper', + 'cp1251', + 'iso8859_7', + 'koi8-r_c', + 'iso8859_4', + 'iso8859_1', + 'cp866', + 'cp437', + 'cp866', + 'cp885', + 'cp866_u', + 'iso8859_1', + 'cp1131', + 'c64_upper', 'c64_lower', - 'c128_upper', - 'c128_lower', - 'atari', - 'pot_noodle', + 'c128_upper', + 'c128_lower', + 'atari', + 'pot_noodle', 'mo_soul', - 'microknight_plus', + 'microknight_plus', 'topaz_plus', 'microknight', 'topaz', @@ -289,7 +289,7 @@ const FONT_ALIAS_TO_SYNCTERM_MAP = { 'topaz' : 'topaz', 'amiga_topaz_1' : 'topaz', 'amiga_topaz_1+' : 'topaz_plus', - 'topazplus' : 'topaz_plus', + 'topazplus' : 'topaz_plus', 'topaz_plus' : 'topaz_plus', 'amiga_topaz_2' : 'topaz', 'amiga_topaz_2+' : 'topaz_plus', @@ -349,7 +349,7 @@ function setCursorStyle(cursorStyle) { return `${ESC_CSI}${ps} q`; } return ''; - + } // Create methods such as up(), nextLine(),... diff --git a/core/archive_util.js b/core/archive_util.js index 6d2644c8..00e48ed8 100644 --- a/core/archive_util.js +++ b/core/archive_util.js @@ -23,7 +23,7 @@ class Archiver { } ok() { - return this.canCompress() && this.canDecompress(); + return this.canCompress() && this.canDecompress(); } can(what) { @@ -41,7 +41,7 @@ class Archiver { } module.exports = class ArchiveUtil { - + constructor() { this.archivers = {}; this.longestSignature = 0; @@ -93,7 +93,7 @@ module.exports = class ArchiveUtil { getArchiver(mimeTypeOrExtension) { mimeTypeOrExtension = resolveMimeType(mimeTypeOrExtension); - + if(!mimeTypeOrExtension) { // lookup returns false on failure return; } @@ -103,21 +103,23 @@ module.exports = class ArchiveUtil { return _.get( Config, [ 'archives', 'archivers', archiveHandler ] ); } } - + haveArchiver(archType) { return this.getArchiver(archType) ? true : false; } - detectTypeWithBuf(buf, cb) { - // :TODO: implement me! + // :TODO: implement me: + /* + detectTypeWithBuf(buf, cb) { } + */ detectType(path, cb) { fs.open(path, 'r', (err, fd) => { if(err) { return cb(err); } - + const buf = new Buffer(this.longestSignature); fs.read(fd, buf, 0, buf.length, 0, (err, bytesRead) => { if(err) { @@ -140,7 +142,7 @@ module.exports = class ArchiveUtil { }); return cb(archFormat ? null : Errors.General('Unknown type'), archFormat); - }); + }); }); } @@ -153,15 +155,15 @@ module.exports = class ArchiveUtil { err = Errors.ExternalProcess(`${action} failed: ${d.trim()}`); } }); - + proc.once('exit', exitCode => { return cb(exitCode ? Errors.ExternalProcess(`${action} failed with exit code: ${exitCode}`) : err); - }); + }); } compressTo(archType, archivePath, files, cb) { const archiver = this.getArchiver(archType); - + if(!archiver) { return cb(Errors.Invalid(`Unknown archive type: ${archType}`)); } @@ -189,13 +191,13 @@ module.exports = class ArchiveUtil { if(!cb && _.isFunction(fileList)) { cb = fileList; fileList = []; - haveFileList = false; + haveFileList = false; } else { haveFileList = true; } const archiver = this.getArchiver(archType); - + if(!archiver) { return cb(Errors.Invalid(`Unknown archive type: ${archType}`)); } @@ -211,7 +213,7 @@ module.exports = class ArchiveUtil { const args = archiver[action].args.map( arg => { return '{fileList}' === arg ? arg : stringFormat(arg, fmtObj); }); - + const fileListPos = args.indexOf('{fileList}'); if(fileListPos > -1) { // replace {fileList} with 0:n sep file list arguments @@ -230,9 +232,9 @@ module.exports = class ArchiveUtil { listEntries(archivePath, archType, cb) { const archiver = this.getArchiver(archType); - + if(!archiver) { - return cb(Errors.Invalid(`Unknown archive type: ${archType}`)); + return cb(Errors.Invalid(`Unknown archive type: ${archType}`)); } const fmtObj = { @@ -240,7 +242,7 @@ module.exports = class ArchiveUtil { }; const args = archiver.list.args.map( arg => stringFormat(arg, fmtObj) ); - + let proc; try { proc = pty.spawn(archiver.list.cmd, args, this.getPtyOpts()); @@ -251,7 +253,7 @@ module.exports = class ArchiveUtil { let output = ''; proc.on('data', data => { // :TODO: hack for: execvp(3) failed.: No such file or directory - + output += data; }); @@ -273,16 +275,16 @@ module.exports = class ArchiveUtil { } return cb(null, entries); - }); + }); } - + getPtyOpts() { return { // :TODO: cwd name : 'enigma-archiver', cols : 80, rows : 24, - env : process.env, + env : process.env, }; } }; diff --git a/core/art.js b/core/art.js index 19e0bafe..546014bd 100644 --- a/core/art.js +++ b/core/art.js @@ -33,7 +33,7 @@ const SUPPORTED_ART_TYPES = { '.pcb' : { name : 'PCBoard', defaultEncoding : 'cp437', eof : 0x1a }, '.bbs' : { name : 'Wildcat', defaultEncoding : 'cp437', eof : 0x1a }, - '.amiga' : { name : 'Amiga', defaultEncoding : 'amiga', eof : 0x1a }, + '.amiga' : { name : 'Amiga', defaultEncoding : 'amiga', eof : 0x1a }, '.txt' : { name : 'Amiga Text', defaultEncoding : 'cp437', eof : 0x1a }, // :TODO: extentions for wwiv, renegade, celerity, syncronet, ... // :TODO: extension for atari @@ -93,7 +93,7 @@ function getArtFromPath(path, options, cb) { } return result; - } + } if(options.readSauce === true) { sauce.readSAUCE(data, (err, sauce) => { @@ -164,7 +164,7 @@ function getArt(name, options, cb) { const bn = paths.basename(file, fext).toLowerCase(); if(options.random) { const suppliedBn = paths.basename(name, fext).toLowerCase(); - + // // Random selection enabled. We'll allow for // basename1.ext, basename2.ext, ... @@ -208,7 +208,7 @@ function getArt(name, options, cb) { return getArtFromPath(readPath, options, cb); } - + return cb(new Error(`No matching art for supplied criteria: ${name}`)); }); } @@ -287,7 +287,7 @@ function display(client, art, options, cb) { return cb(null, mciMap, extraInfo); } - if(!options.disableMciCache) { + if(!options.disableMciCache) { artHash = xxhash.hash(new Buffer(art), 0xCAFEBABE); // see if we have a mciMap cached for this art @@ -307,7 +307,7 @@ function display(client, art, options, cb) { if(mciCprQueue.length > 0) { mciMap[mciCprQueue.shift()].position = pos; - if(parseComplete && 0 === mciCprQueue.length) { + if(parseComplete && 0 === mciCprQueue.length) { return completed(); } } @@ -345,7 +345,7 @@ function display(client, art, options, cb) { }); } - ansiParser.on('literal', literal => client.term.write(literal, false) ); + ansiParser.on('literal', literal => client.term.write(literal, false) ); ansiParser.on('control', control => client.term.rawWrite(control) ); ansiParser.on('complete', () => { @@ -353,7 +353,7 @@ function display(client, art, options, cb) { if(0 === mciCprQueue.length) { return completed(); - } + } }); let initSeq = ''; diff --git a/core/asset.js b/core/asset.js index 9f2831b7..3f44a604 100644 --- a/core/asset.js +++ b/core/asset.js @@ -31,7 +31,7 @@ const ALL_ASSETS = [ const ASSET_RE = new RegExp('\\@(' + ALL_ASSETS.join('|') + ')\\:([\\w\\d\\.]*)(?:\\/([\\w\\d\\_]+))*'); -function parseAsset(s) { +function parseAsset(s) { const m = ASSET_RE.exec(s); if(m) { @@ -68,7 +68,7 @@ function getAssetWithShorthand(spec, defaultType) { function getArtAsset(spec) { const asset = getAssetWithShorthand(spec, 'art'); - + if(!asset) { return null; } @@ -79,7 +79,7 @@ function getArtAsset(spec) { function getModuleAsset(spec) { const asset = getAssetWithShorthand(spec, 'systemModule'); - + if(!asset) { return null; } @@ -105,7 +105,7 @@ function resolveConfigAsset(spec) { return conf; } else { return spec; - } + } } function resolveSystemStatAsset(spec) { diff --git a/core/bbs.js b/core/bbs.js index 43bf7cf3..c2f54802 100644 --- a/core/bbs.js +++ b/core/bbs.js @@ -182,7 +182,7 @@ function initialize(cb) { return database.initializeDatabases(callback); }, function initMimeTypes(callback) { - return require('./mime_util.js').startup(callback); + return require('./mime_util.js').startup(callback); }, function initStatLog(callback) { return require('./stat_log.js').init(callback); diff --git a/core/bbs_link.js b/core/bbs_link.js index be341115..15416c2e 100644 --- a/core/bbs_link.js +++ b/core/bbs_link.js @@ -23,10 +23,10 @@ const packageJson = require('../package.json'); authCode: XXXXX schemeCode: XXXX door: lord - + // default hoss: games.bbslink.net host: games.bbslink.net - + // defualt port: 23 port: 23 } @@ -49,7 +49,7 @@ exports.getModule = class BBSLinkModule extends MenuModule { this.config = options.menuConfig.config; this.config.host = this.config.host || 'games.bbslink.net'; this.config.port = this.config.port || 23; - } + } initSequence() { let token; @@ -141,7 +141,7 @@ exports.getModule = class BBSLinkModule extends MenuModule { self.client.once('end', function clientEnd() { self.client.log.info('Connection ended. Terminating BBSLink connection'); clientTerminated = true; - bridgeConnection.end(); + bridgeConnection.end(); }); }); @@ -170,7 +170,7 @@ exports.getModule = class BBSLinkModule extends MenuModule { ], function complete(err) { if(err) { - self.client.log.warn( { error : err.toString() }, 'BBSLink connection error'); + self.client.log.warn( { error : err.toString() }, 'BBSLink connection error'); } if(!clientTerminated) { diff --git a/core/bbs_list.js b/core/bbs_list.js index 33a7ff59..5c81f478 100644 --- a/core/bbs_list.js +++ b/core/bbs_list.js @@ -4,7 +4,7 @@ // ENiGMA½ const MenuModule = require('./menu_module.js').MenuModule; -const { +const { getModDatabasePath, getTransactionDatabase } = require('./database.js'); @@ -39,7 +39,7 @@ const MciViewIds = { SelectedBBSLoc : 6, SelectedBBSSoftware : 7, SelectedBBSNotes : 8, - SelectedBBSSubmitter : 9, + SelectedBBSSubmitter : 9, }, add : { BBSName : 1, @@ -49,7 +49,7 @@ const MciViewIds = { Location : 5, Software : 6, Notes : 7, - Error : 8, + Error : 8, } }; @@ -190,12 +190,12 @@ exports.getModule = class BBSListModule extends MenuModule { drawSelectedEntry(entry) { if(!entry) { - Object.keys(SELECTED_MCI_NAME_TO_ENTRY).forEach(mciName => { + Object.keys(SELECTED_MCI_NAME_TO_ENTRY).forEach(mciName => { this.setViewText('view', MciViewIds.view[mciName], ''); }); } else { const youSubmittedFormat = this.menuConfig.youSubmittedFormat || '{submitter} (You!)'; - + Object.keys(SELECTED_MCI_NAME_TO_ENTRY).forEach(mciName => { const t = entry[SELECTED_MCI_NAME_TO_ENTRY[mciName]]; if(MciViewIds.view[mciName]) { @@ -270,7 +270,7 @@ exports.getModule = class BBSListModule extends MenuModule { (err, row) => { if (!err) { self.entries.push({ - id : row.id, + id : row.id, bbsName : row.bbs_name, sysOp : row.sysop, telnet : row.telnet, @@ -306,9 +306,9 @@ exports.getModule = class BBSListModule extends MenuModule { entriesView.on('index update', idx => { const entry = self.entries[idx]; - + self.drawSelectedEntry(entry); - + if(!entry) { self.selectedBBS = -1; } else { diff --git a/core/button_view.js b/core/button_view.js index 570adc09..d5b858c7 100644 --- a/core/button_view.js +++ b/core/button_view.js @@ -22,7 +22,7 @@ ButtonView.prototype.onKeyPress = function(ch, key) { if(this.isKeyMapped('accept', key.name) || ' ' === ch) { this.submitData = 'accept'; this.emit('action', 'accept'); - delete this.submitData; + delete this.submitData; } else { ButtonView.super_.prototype.onKeyPress.call(this, ch, key); } diff --git a/core/client.js b/core/client.js index 424748a6..58700c8f 100644 --- a/core/client.js +++ b/core/client.js @@ -52,8 +52,8 @@ exports.Client = Client; // Resources & Standards: // * http://www.ansi-bbs.org/ansi-bbs-core-server.html // -const RE_DSR_RESPONSE_ANYWHERE = /(?:\u001b\[)([0-9\;]+)(R)/; -const RE_DEV_ATTR_RESPONSE_ANYWHERE = /(?:\u001b\[)[\=\?]([0-9a-zA-Z\;]+)(c)/; +const RE_DSR_RESPONSE_ANYWHERE = /(?:\u001b\[)([0-9;]+)(R)/; +const RE_DEV_ATTR_RESPONSE_ANYWHERE = /(?:\u001b\[)[=?]([0-9a-zA-Z;]+)(c)/; const RE_META_KEYCODE_ANYWHERE = /(?:\u001b)([a-zA-Z0-9])/; const RE_META_KEYCODE = new RegExp('^' + RE_META_KEYCODE_ANYWHERE.source + '$'); const RE_FUNCTION_KEYCODE_ANYWHERE = new RegExp('(?:\u001b+)(O|N|\\[|\\[\\[)(?:' + [ @@ -64,19 +64,19 @@ const RE_FUNCTION_KEYCODE_ANYWHERE = new RegExp('(?:\u001b+)(O|N|\\[|\\[\\[)(?:' const RE_FUNCTION_KEYCODE = new RegExp('^' + RE_FUNCTION_KEYCODE_ANYWHERE.source); const RE_ESC_CODE_ANYWHERE = new RegExp( [ - RE_FUNCTION_KEYCODE_ANYWHERE.source, - RE_META_KEYCODE_ANYWHERE.source, + RE_FUNCTION_KEYCODE_ANYWHERE.source, + RE_META_KEYCODE_ANYWHERE.source, RE_DSR_RESPONSE_ANYWHERE.source, RE_DEV_ATTR_RESPONSE_ANYWHERE.source, /\u001b./.source ].join('|')); -function Client(input, output) { +function Client(/*input, output*/) { stream.call(this); const self = this; - + this.user = new User(); this.currentTheme = { info : { name : 'N/A', description : 'None' } }; this.lastKeyPressMs = Date.now(); @@ -125,9 +125,9 @@ function Client(input, output) { if(!termClient) { if(_.startsWith(deviceAttr, '67;84;101;114;109')) { - // + // // See https://github.com/protomouse/synchronet/blob/master/src/conio/cterm.txt - // + // // Known clients: // * SyncTERM // @@ -139,11 +139,11 @@ function Client(input, output) { }; this.isMouseInput = function(data) { - return /\x1b\[M/.test(data) || - /\u001b\[M([\x00\u0020-\uffff]{3})/.test(data) || + return /\x1b\[M/.test(data) || // eslint-disable-line no-control-regex + /\u001b\[M([\x00\u0020-\uffff]{3})/.test(data) || // eslint-disable-line no-control-regex /\u001b\[(\d+;\d+;\d+)M/.test(data) || /\u001b\[<(\d+;\d+;\d+)([mM])/.test(data) || - /\u001b\[<(\d+;\d+;\d+;\d+)&w/.test(data) || + /\u001b\[<(\d+;\d+;\d+;\d+)&w/.test(data) || /\u001b\[24([0135])~\[(\d+),(\d+)\]\r/.test(data) || /\u001b\[(O|I)/.test(data); }; @@ -163,7 +163,7 @@ function Client(input, output) { 'OE' : { name : 'clear' }, 'OF' : { name : 'end' }, 'OH' : { name : 'home' }, - + // xterm/rxvt '[11~' : { name : 'f1' }, '[12~' : { name : 'f2' }, @@ -290,7 +290,7 @@ function Client(input, output) { if(self.cprOffset) { cprArgs[0] = cprArgs[0] + self.cprOffset; cprArgs[1] = cprArgs[1] + self.cprOffset; - } + } self.emit('cursor position report', cprArgs); } } @@ -299,7 +299,7 @@ function Client(input, output) { var termClient = self.getTermClient(parts[1]); if(termClient) { self.term.termClient = termClient; - } + } } else if('\r' === s) { key.name = 'return'; } else if('\n' === s) { @@ -347,10 +347,10 @@ function Client(input, output) { key.meta = true; key.shift = /^[A-Z]$/.test(parts[1]); } else if((parts = RE_FUNCTION_KEYCODE.exec(s))) { - var code = + var code = (parts[1] || '') + (parts[2] || '') + (parts[4] || '') + (parts[9] || ''); - + var modifier = (parts[3] || parts[8] || 1) - 1; key.ctrl = !!(modifier & 4); @@ -375,7 +375,7 @@ function Client(input, output) { // // Adjust name for CTRL/Shift/Meta modifiers // - key.name = + key.name = (key.ctrl ? 'ctrl + ' : '') + (key.meta ? 'meta + ' : '') + (key.shift ? 'shift + ' : '') + @@ -446,7 +446,7 @@ Client.prototype.end = function () { } clearInterval(this.idleCheck); - + try { // // We can end up calling 'end' before TTY/etc. is established, e.g. with SSH @@ -482,7 +482,7 @@ Client.prototype.isLocal = function() { /////////////////////////////////////////////////////////////////////////////// // :TODO: getDefaultHandler(name) -- handlers in default_handlers.js or something -Client.prototype.defaultHandlerMissingMod = function(err) { +Client.prototype.defaultHandlerMissingMod = function() { var self = this; function handler(err) { @@ -493,12 +493,12 @@ Client.prototype.defaultHandlerMissingMod = function(err) { self.term.write('This has been logged for your SysOp to review.\n'); self.term.write('\nGoodbye!\n'); - + //self.term.write(err); //if(miscUtil.isDevelopment() && err.stack) { // self.term.write('\n' + err.stack + '\n'); - //} + //} self.end(); } @@ -516,8 +516,8 @@ Client.prototype.terminalSupports = function(query) { case 'vtx_hyperlink' : return 'vtx' === termClient; - - default : + + default : return false; } }; diff --git a/core/client_connections.js b/core/client_connections.js index 7e74e29d..d81d0922 100644 --- a/core/client_connections.js +++ b/core/client_connections.js @@ -95,7 +95,7 @@ function removeClient(client) { clientId : client.session.id }, 'Client disconnected' - ); + ); Events.emit('codes.l33t.enigma.system.disconnected', { client : client, connectionCount : clientConnections.length } ); } diff --git a/core/client_term.js b/core/client_term.js index b313841e..b944988d 100644 --- a/core/client_term.js +++ b/core/client_term.js @@ -15,8 +15,6 @@ exports.ClientTerminal = ClientTerminal; function ClientTerminal(output) { this.output = output; - var self = this; - var outputEncoding = 'cp437'; assert(iconv.encodingExists(outputEncoding)); @@ -56,7 +54,7 @@ function ClientTerminal(output) { }, set : function(ttype) { termType = ttype.toLowerCase(); - + if(this.isANSI()) { this.outputEncoding = 'cp437'; } else { @@ -137,7 +135,7 @@ ClientTerminal.prototype.isANSI = function() { // // syncterm: // * SyncTERM - // + // // xterm: // * PuTTY // @@ -168,7 +166,7 @@ ClientTerminal.prototype.rawWrite = function(s, cb) { if(cb) { return cb(err); } - + if(err) { Log.warn( { error : err.message }, 'Failed writing to socket'); } @@ -178,18 +176,18 @@ ClientTerminal.prototype.rawWrite = function(s, cb) { ClientTerminal.prototype.pipeWrite = function(s, spec, cb) { spec = spec || 'renegade'; - + var conv = { enigma : enigmaToAnsi, renegade : renegadeToAnsi, }[spec] || renegadeToAnsi; - + this.write(conv(s, this), null, cb); // null = use default for |convertLineFeeds| }; ClientTerminal.prototype.encode = function(s, convertLineFeeds) { convertLineFeeds = _.isBoolean(convertLineFeeds) ? convertLineFeeds : this.convertLF; - + if(convertLineFeeds && _.isString(s)) { s = s.replace(/\n/g, '\r\n'); } diff --git a/core/color_codes.js b/core/color_codes.js index 2e368aa3..db9f4fe5 100644 --- a/core/color_codes.js +++ b/core/color_codes.js @@ -68,14 +68,14 @@ function enigmaToAnsi(s, client) { attr = ansi.sgr(['normal', val - 8, 'bold']); } - result += s.substr(lastIndex, m.index - lastIndex) + attr; + result += s.substr(lastIndex, m.index - lastIndex) + attr; } lastIndex = re.lastIndex; } result = (0 === result.length ? s : result + s.substr(lastIndex)); - + return result; } @@ -145,7 +145,7 @@ function renegadeToAnsi(s, client) { } // convert to number - val = parseInt(val, 10); + val = parseInt(val, 10); if(isNaN(val)) { val = getPredefinedMCIValue(client, m[1]) || ('|' + m[1]); // value itself or literal } @@ -160,7 +160,7 @@ function renegadeToAnsi(s, client) { lastIndex = re.lastIndex; } - return (0 === result.length ? s : result + s.substr(lastIndex)); + return (0 === result.length ? s : result + s.substr(lastIndex)); } // @@ -180,7 +180,7 @@ function renegadeToAnsi(s, client) { // * http://wiki.synchro.net/custom:colors // function controlCodesToAnsi(s, client) { - const RE = /(\|([A-Z0-9]{2})|\|)|(\@X([0-9A-F]{2}))|(\@([0-9A-F]{2})\@)|(\x03[0-9]|\x03)/g; // eslint-disable-line no-control-regex + const RE = /(\|([A-Z0-9]{2})|\|)|(@X([0-9A-F]{2}))|(@([0-9A-F]{2})@)|(\x03[0-9]|\x03)/g; // eslint-disable-line no-control-regex let m; let result = ''; diff --git a/core/combatnet.js b/core/combatnet.js index 6cde9c7b..217e6d17 100644 --- a/core/combatnet.js +++ b/core/combatnet.js @@ -25,10 +25,10 @@ exports.getModule = class CombatNetModule extends MenuModule { this.config.host = this.config.host || 'bbs.combatnet.us'; this.config.rloginPort = this.config.rloginPort || 4513; } - + initSequence() { const self = this; - + async.series( [ function validateConfig(callback) { @@ -45,59 +45,59 @@ exports.getModule = class CombatNetModule extends MenuModule { self.client.term.write('Connecting to CombatNet, please wait...\n'); const restorePipeToNormal = function() { - self.client.term.output.removeListener('data', sendToRloginBuffer); + self.client.term.output.removeListener('data', sendToRloginBuffer); }; - const rlogin = new RLogin( - { 'clientUsername' : self.config.password, - 'serverUsername' : `${self.config.bbsTag}${self.client.user.username}`, - 'host' : self.config.host, - 'port' : self.config.rloginPort, - 'terminalType' : self.client.term.termClient, - 'terminalSpeed' : 57600 - } - ); + const rlogin = new RLogin( + { 'clientUsername' : self.config.password, + 'serverUsername' : `${self.config.bbsTag}${self.client.user.username}`, + 'host' : self.config.host, + 'port' : self.config.rloginPort, + 'terminalType' : self.client.term.termClient, + 'terminalSpeed' : 57600 + } + ); - // If there was an error ... - rlogin.on('error', err => { - self.client.log.info(`CombatNet rlogin client error: ${err.message}`); - restorePipeToNormal(); - callback(err); - }); + // If there was an error ... + rlogin.on('error', err => { + self.client.log.info(`CombatNet rlogin client error: ${err.message}`); + restorePipeToNormal(); + return callback(err); + }); - // If we've been disconnected ... - rlogin.on('disconnect', () => { - self.client.log.info(`Disconnected from CombatNet`); - restorePipeToNormal(); - callback(null); - }); + // If we've been disconnected ... + rlogin.on('disconnect', () => { + self.client.log.info('Disconnected from CombatNet'); + restorePipeToNormal(); + return callback(null); + }); - function sendToRloginBuffer(buffer) { - rlogin.send(buffer); - }; + function sendToRloginBuffer(buffer) { + rlogin.send(buffer); + } - rlogin.on("connect", - /* The 'connect' event handler will be supplied with one argument, + rlogin.on('connect', + /* The 'connect' event handler will be supplied with one argument, a boolean indicating whether or not the connection was established. */ - function(state) { - if(state) { - self.client.log.info('Connected to CombatNet'); - self.client.term.output.on('data', sendToRloginBuffer); + function(state) { + if(state) { + self.client.log.info('Connected to CombatNet'); + self.client.term.output.on('data', sendToRloginBuffer); - } else { - return callback(new Error('Failed to establish establish CombatNet connection')); - } - } - ); + } else { + return callback(new Error('Failed to establish establish CombatNet connection')); + } + } + ); - // If data (a Buffer) has been received from the server ... - rlogin.on("data", (data) => { - self.client.term.rawWrite(data); - }); + // If data (a Buffer) has been received from the server ... + rlogin.on('data', (data) => { + self.client.term.rawWrite(data); + }); - // connect... - rlogin.connect(); + // connect... + rlogin.connect(); // note: no explicit callback() until we're finished! } @@ -106,10 +106,10 @@ exports.getModule = class CombatNetModule extends MenuModule { if(err) { self.client.log.warn( { error : err.message }, 'CombatNet error'); } - + // if the client is still here, go to previous self.prevMenu(); } ); - } + } }; diff --git a/core/conf_area_util.js b/core/conf_area_util.js index 5dabfb73..6b71061b 100644 --- a/core/conf_area_util.js +++ b/core/conf_area_util.js @@ -10,7 +10,7 @@ exports.sortAreasOrConfs = sortAreasOrConfs; // Method for sorting message, file, etc. areas and confs // If the sort key is present and is a number, sort in numerical order; // Otherwise, use a locale comparison on the sort key or name as a fallback -// +// function sortAreasOrConfs(areasOrConfs, type) { let entryA; let entryB; diff --git a/core/config.js b/core/config.js index 62ce6032..79824db5 100644 --- a/core/config.js +++ b/core/config.js @@ -653,12 +653,12 @@ function getDefaultConfig() { // FILE_ID.DIZ - https://en.wikipedia.org/wiki/FILE_ID.DIZ // Some groups include a FILE_ID.ANS. We try to use that over FILE_ID.DIZ if available. desc : [ - '^[^/\]*FILE_ID\.ANS$', '^[^/\]*FILE_ID\.DIZ$', '^[^/\]*DESC\.SDI$', '^[^/\]*DESCRIPT\.ION$', '^[^/\]*FILE\.DES$', '^[^/\]*FILE\.SDI$', '^[^/\]*DISK\.ID$' + '^[^/\]*FILE_ID\.ANS$', '^[^/\]*FILE_ID\.DIZ$', '^[^/\]*DESC\.SDI$', '^[^/\]*DESCRIPT\.ION$', '^[^/\]*FILE\.DES$', '^[^/\]*FILE\.SDI$', '^[^/\]*DISK\.ID$' // eslint-disable-line no-useless-escape ], // common README filename - https://en.wikipedia.org/wiki/README descLong : [ - '^[^/\]*\.NFO$', '^[^/\]*README\.1ST$', '^[^/\]*README\.NOW$', '^[^/\]*README\.TXT$', '^[^/\]*READ\.ME$', '^[^/\]*README$', '^[^/\]*README\.md$' + '^[^/\]*\.NFO$', '^[^/\]*README\.1ST$', '^[^/\]*README\.NOW$', '^[^/\]*README\.TXT$', '^[^/\]*READ\.ME$', '^[^/\]*README$', '^[^/\]*README\.md$' // eslint-disable-line no-useless-escape ], }, diff --git a/core/config_cache.js b/core/config_cache.js index 8b57e125..875e1b2e 100644 --- a/core/config_cache.js +++ b/core/config_cache.js @@ -58,7 +58,7 @@ util.inherits(ConfigCache, events.EventEmitter); ConfigCache.prototype.getConfigWithOptions = function(options, cb) { assert(_.isString(options.filePath)); -// var self = this; + // var self = this; var isCached = (options.filePath in this.cache); if(options.forceReCache || !isCached) { diff --git a/core/connect.js b/core/connect.js index b94fa586..aae1b8c6 100644 --- a/core/connect.js +++ b/core/connect.js @@ -98,7 +98,7 @@ function ansiQueryTermSizeIfNeeded(client, cb) { source : 'ANSI CPR' }, 'Window size updated' - ); + ); return done(null); }; diff --git a/core/crc.js b/core/crc.js index 886dad1d..e4bd8551 100644 --- a/core/crc.js +++ b/core/crc.js @@ -10,7 +10,7 @@ exports.CRC32 = class CRC32 { } update(input) { - input = Buffer.isBuffer(input) ? input : Buffer.from(input, 'binary'); + input = Buffer.isBuffer(input) ? input : Buffer.from(input, 'binary'); return input.length > 10240 ? this.update_8(input) : this.update_4(input); } @@ -47,7 +47,7 @@ exports.CRC32 = class CRC32 { this.crc = (this.crc >>> 8) ^ CRC32_TABLE[ (this.crc ^ input[i++] ) & 0xff ]; } } - + finalize() { return (this.crc ^ (-1)) >>> 0; } diff --git a/core/database.js b/core/database.js index 14b3bf95..10331fc0 100644 --- a/core/database.js +++ b/core/database.js @@ -36,12 +36,12 @@ function getModDatabasePath(moduleInfo, suffix) { // Mods that use a database are stored in Config.paths.modsDb (e.g. enigma-bbs/db/mods) // We expect that moduleInfo defines packageName which will be the base of the modules // filename. An optional suffix may be supplied as well. - // - const HOST_RE = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/; + // + const HOST_RE = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/; assert(_.isObject(moduleInfo)); assert(_.isString(moduleInfo.packageName), 'moduleInfo must define "packageName"!'); - + let full = moduleInfo.packageName; if(suffix) { full += `.${suffix}`; @@ -198,7 +198,7 @@ const DB_INIT_TABLE = { DELETE FROM message_fts WHERE docid=old.rowid; END;` ); - + dbs.message.run( `CREATE TRIGGER IF NOT EXISTS message_before_delete BEFORE DELETE ON message BEGIN DELETE FROM message_fts WHERE docid=old.rowid; @@ -256,14 +256,14 @@ const DB_INIT_TABLE = { UNIQUE(user_id, area_tag) );` ); - + dbs.message.run( `CREATE TABLE IF NOT EXISTS message_area_last_scan ( scan_toss VARCHAR NOT NULL, area_tag VARCHAR NOT NULL, message_id INTEGER NOT NULL, UNIQUE(scan_toss, area_tag) - );` + );` ); return cb(null); diff --git a/core/door.js b/core/door.js index 5670db1e..525a7a02 100644 --- a/core/door.js +++ b/core/door.js @@ -20,7 +20,7 @@ function Door(client, exeInfo) { this.exeInfo = exeInfo; this.exeInfo.encoding = this.exeInfo.encoding || 'cp437'; this.exeInfo.encoding = this.exeInfo.encoding.toLowerCase(); - let restored = false; + let restored = false; // // Members of exeInfo: @@ -52,7 +52,7 @@ function Door(client, exeInfo) { }; this.prepareSocketIoServer = function(cb) { - if('socket' === self.exeInfo.io) { + if('socket' === self.exeInfo.io) { const sockServer = createServer(conn => { sockServer.getConnections( (err, count) => { @@ -60,11 +60,11 @@ function Door(client, exeInfo) { // We expect only one connection from our DOOR/emulator/etc. if(!err && count <= 1) { self.client.term.output.pipe(conn); - + conn.on('data', self.doorDataHandler); conn.once('end', () => { - return self.restoreIo(conn); + return self.restoreIo(conn); }); conn.once('error', err => { @@ -117,7 +117,7 @@ Door.prototype.run = function() { rows : self.client.term.termHeight, // :TODO: cwd env : self.exeInfo.env, - }); + }); if('stdio' === self.exeInfo.io) { self.client.log.debug('Using stdio for door I/O'); diff --git a/core/door_party.js b/core/door_party.js index 762f626b..a64f92c8 100644 --- a/core/door_party.js +++ b/core/door_party.js @@ -24,13 +24,13 @@ exports.getModule = class DoorPartyModule extends MenuModule { this.config = options.menuConfig.config; this.config.host = this.config.host || 'dp.throwbackbbs.com'; this.config.sshPort = this.config.sshPort || 2022; - this.config.rloginPort = this.config.rloginPort || 513; + this.config.rloginPort = this.config.rloginPort || 513; } - + initSequence() { let clientTerminated; const self = this; - + async.series( [ function validateConfig(callback) { @@ -48,26 +48,26 @@ exports.getModule = class DoorPartyModule extends MenuModule { function establishSecureConnection(callback) { self.client.term.write(resetScreen()); self.client.term.write('Connecting to DoorParty, please wait...\n'); - + const sshClient = new SSHClient(); - + let pipeRestored = false; let pipedStream; const restorePipe = function() { if(pipedStream && !pipeRestored && !clientTerminated) { - self.client.term.output.unpipe(pipedStream); + self.client.term.output.unpipe(pipedStream); self.client.term.output.resume(); - } - }; - + } + }; + sshClient.on('ready', () => { // track client termination so we can clean up early self.client.once('end', () => { self.client.log.info('Connection ended. Terminating DoorParty connection'); clientTerminated = true; - sshClient.end(); + sshClient.end(); }); - + // establish tunnel for rlogin sshClient.forwardOut('127.0.0.1', self.config.sshPort, self.config.host, self.config.rloginPort, (err, stream) => { if(err) { @@ -79,17 +79,17 @@ exports.getModule = class DoorPartyModule extends MenuModule { // DoorParty wants the "server username" portion to be in the format of [BBS_TAG]USERNAME, e.g. // [XA]nuskooler // - const rlogin = `\x00${self.client.user.username}\x00[${self.config.bbsTag}]${self.client.user.username}\x00${self.client.term.termType}\x00`; + const rlogin = `\x00${self.client.user.username}\x00[${self.config.bbsTag}]${self.client.user.username}\x00${self.client.term.termType}\x00`; stream.write(rlogin); - + pipedStream = stream; // :TODO: this is hacky... self.client.term.output.pipe(stream); - + stream.on('data', d => { // :TODO: we should just pipe this... self.client.term.rawWrite(d); }); - + stream.on('close', () => { restorePipe(); sshClient.end(); @@ -100,32 +100,32 @@ exports.getModule = class DoorPartyModule extends MenuModule { sshClient.on('error', err => { self.client.log.info(`DoorParty SSH client error: ${err.message}`); }); - + sshClient.on('close', () => { restorePipe(); callback(null); }); - + sshClient.connect( { host : self.config.host, port : self.config.sshPort, username : self.config.username, password : self.config.password, }); - + // note: no explicit callback() until we're finished! - } + } ], err => { if(err) { self.client.log.warn( { error : err.message }, 'DoorParty error'); } - + // if the client is stil here, go to previous if(!clientTerminated) { self.prevMenu(); } } ); - } + } }; diff --git a/core/download_queue.js b/core/download_queue.js index 6bfbd47f..0f45b04d 100644 --- a/core/download_queue.js +++ b/core/download_queue.js @@ -59,14 +59,14 @@ module.exports = class DownloadQueue { } toProperty() { return JSON.stringify(this.client.user.downloadQueue); } - + loadFromProperty(prop) { try { this.client.user.downloadQueue = JSON.parse(prop); } catch(e) { this.client.user.downloadQueue = []; - this.client.log.error( { error : e.message, property : prop }, 'Failed parsing download queue property'); + this.client.log.error( { error : e.message, property : prop }, 'Failed parsing download queue property'); } - } + } }; diff --git a/core/edit_text_view.js b/core/edit_text_view.js index 8e55ae53..0db02638 100644 --- a/core/edit_text_view.js +++ b/core/edit_text_view.js @@ -16,7 +16,7 @@ function EditTextView(options) { options.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true); options.cursorStyle = miscUtil.valueWithDefault(options.cursorStyle, 'steady block'); options.resizable = false; - + TextView.call(this, options); this.cursorPos = { row : 0, col : 0 }; @@ -44,7 +44,7 @@ EditTextView.prototype.onKeyPress = function(ch, key) { } } } - + return EditTextView.super_.prototype.onKeyPress.call(this, ch, key); } else if(this.isKeyMapped('clearLine', key.name)) { this.text = ''; diff --git a/core/enig_error.js b/core/enig_error.js index 49627b9c..b0dd2335 100644 --- a/core/enig_error.js +++ b/core/enig_error.js @@ -14,7 +14,7 @@ class EnigError extends Error { if(typeof Error.captureStackTrace === 'function') { Error.captureStackTrace(this, this.constructor); } else { - this.stack = (new Error(message)).stack; + this.stack = (new Error(message)).stack; } } } diff --git a/core/enigma_assert.js b/core/enigma_assert.js index 2001825d..9217ea49 100644 --- a/core/enigma_assert.js +++ b/core/enigma_assert.js @@ -3,14 +3,14 @@ // ENiGMA½ const Config = require('./config.js').config; -const Log = require('./logger.js').log; +const Log = require('./logger.js').log; // deps const assert = require('assert'); module.exports = function(condition, message) { if(Config.debug.assertsEnabled) { - assert.apply(this, arguments); + assert.apply(this, arguments); } else if(!(condition)) { const stack = new Error().stack; Log.error( { condition : condition, stack : stack }, message || 'Assertion failed' ); diff --git a/core/erc_client.js b/core/erc_client.js index 4fb549f6..ccc70199 100644 --- a/core/erc_client.js +++ b/core/erc_client.js @@ -37,12 +37,12 @@ var MciViewIds = { function ErcClientModule(options) { MenuModule.prototype.ctorShim.call(this, options); - const self = this; + const self = this; this.config = options.menuConfig.config; this.chatEntryFormat = this.config.chatEntryFormat || '[{bbsTag}] {userName}: {message}'; - this.systemEntryFormat = this.config.systemEntryFormat || '[*SYSTEM*] {message}'; - + this.systemEntryFormat = this.config.systemEntryFormat || '[*SYSTEM*] {message}'; + this.finishedLoading = function() { async.waterfall( [ @@ -63,12 +63,12 @@ function ErcClientModule(options) { }; const chatMessageView = self.viewControllers.menu.getView(MciViewIds.ChatDisplay); - + chatMessageView.setText('Connecting to server...'); chatMessageView.redraw(); - + self.viewControllers.menu.switchFocus(MciViewIds.InputArea); - + // :TODO: Track actual client->enig connection for optional prevMenu @ final CB self.chatConnection = net.createConnection(connectOpts.port, connectOpts.host); @@ -98,12 +98,12 @@ function ErcClientModule(options) { } chatMessageView.addText(text); - + if(chatMessageView.getLineCount() > 30) { // :TODO: should probably be ChatDisplay.height? chatMessageView.deleteLine(0); chatMessageView.scrollDown(); } - + chatMessageView.redraw(); self.viewControllers.menu.switchFocus(MciViewIds.InputArea); } diff --git a/core/event_scheduler.js b/core/event_scheduler.js index 8b3d3239..0366d5ba 100644 --- a/core/event_scheduler.js +++ b/core/event_scheduler.js @@ -24,8 +24,8 @@ exports.moduleInfo = { author : 'NuSkooler', }; -const SCHEDULE_REGEXP = /(?:^|or )?(@watch\:)([^\0]+)?$/; -const ACTION_REGEXP = /\@(method|execute)\:([^\0]+)?$/; +const SCHEDULE_REGEXP = /(?:^|or )?(@watch:)([^\0]+)?$/; +const ACTION_REGEXP = /@(method|execute):([^\0]+)?$/; class ScheduledEvent { constructor(events, name) { @@ -34,32 +34,32 @@ class ScheduledEvent { this.action = this.parseActionSpec(events[name].action); if(this.action) { this.action.args = events[name].args || []; - } + } } - + get isValid() { if((!this.schedule || (!this.schedule.sched && !this.schedule.watchFile)) || !this.action) { return false; } - + if('method' === this.action.type && !this.action.location) { return false; } - - return true; + + return true; } - + parseScheduleString(schedStr) { if(!schedStr) { return false; } - + let schedule = {}; - + const m = SCHEDULE_REGEXP.exec(schedStr); if(m) { schedStr = schedStr.substr(0, m.index).trim(); - + if('@watch:' === m[1]) { schedule.watchFile = m[2]; } @@ -69,15 +69,15 @@ class ScheduledEvent { const sched = later.parse.text(schedStr); if(-1 === sched.error) { schedule.sched = sched; - } + } } - + // return undefined if we couldn't parse out anything useful if(!_.isEmpty(schedule)) { return schedule; } } - + parseActionSpec(actionSpec) { if(actionSpec) { if('@' === actionSpec[0]) { @@ -86,7 +86,7 @@ class ScheduledEvent { if(m[2].indexOf(':') > -1) { const parts = m[2].split(':'); return { - type : m[1], + type : m[1], location : parts[0], what : parts[1], }; @@ -98,12 +98,12 @@ class ScheduledEvent { } } } else { - return { + return { type : 'execute', what : actionSpec, }; - } - } + } + } } executeAction(reason, cb) { @@ -119,14 +119,14 @@ class ScheduledEvent { { error : err.toString(), eventName : this.name, action : this.action }, 'Error performing scheduled event action'); } - + return cb(err); }); } catch(e) { Log.warn( { error : e.toString(), eventName : this.name, action : this.action }, 'Failed to perform scheduled event action'); - + return cb(e); } } else if('execute' === this.action.type) { @@ -135,18 +135,18 @@ class ScheduledEvent { name : this.name, cols : 80, rows : 24, - env : process.env, + env : process.env, }; const proc = pty.spawn(this.action.what, this.action.args, opts); - proc.once('exit', exitCode => { + proc.once('exit', exitCode => { if(exitCode) { Log.warn( { eventName : this.name, action : this.action, exitCode : exitCode }, 'Bad exit code while performing scheduled event action'); } - return cb(exitCode ? new Error(`Bad exit code while performing scheduled event action: ${exitCode}`) : null); + return cb(exitCode ? new Error(`Bad exit code while performing scheduled event action: ${exitCode}`) : null); }); } } @@ -154,58 +154,58 @@ class ScheduledEvent { function EventSchedulerModule(options) { PluginModule.call(this, options); - + if(_.has(Config, 'eventScheduler')) { this.moduleConfig = Config.eventScheduler; } - + const self = this; this.runningActions = new Set(); - + this.performAction = function(schedEvent, reason) { if(self.runningActions.has(schedEvent.name)) { return; // already running - } - + } + self.runningActions.add(schedEvent.name); schedEvent.executeAction(reason, () => { self.runningActions.delete(schedEvent.name); - }); + }); }; } // convienence static method for direct load + start EventSchedulerModule.loadAndStart = function(cb) { const loadModuleEx = require('./module_util.js').loadModuleEx; - + const loadOpts = { name : path.basename(__filename, '.js'), path : __dirname, }; - + loadModuleEx(loadOpts, (err, mod) => { if(err) { return cb(err); } - + const modInst = new mod.getModule(); modInst.startup( err => { return cb(err, modInst); - }); + }); }); }; EventSchedulerModule.prototype.startup = function(cb) { - + this.eventTimers = []; const self = this; - + if(this.moduleConfig && _.has(this.moduleConfig, 'events')) { const events = Object.keys(this.moduleConfig.events).map( name => { return new ScheduledEvent(this.moduleConfig.events, name); }); - + events.forEach( schedEvent => { if(!schedEvent.isValid) { Log.warn( { eventName : schedEvent.name }, 'Invalid scheduled event entry'); @@ -213,7 +213,7 @@ EventSchedulerModule.prototype.startup = function(cb) { } Log.debug( - { + { eventName : schedEvent.name, schedule : this.moduleConfig.events[schedEvent.name].schedule, action : schedEvent.action, @@ -222,9 +222,9 @@ EventSchedulerModule.prototype.startup = function(cb) { 'Scheduled event loaded' ); - if(schedEvent.schedule.sched) { + if(schedEvent.schedule.sched) { this.eventTimers.push(later.setInterval( () => { - self.performAction(schedEvent, 'Schedule'); + self.performAction(schedEvent, 'Schedule'); }, schedEvent.schedule.sched)); } @@ -255,7 +255,7 @@ EventSchedulerModule.prototype.startup = function(cb) { } }); } - + cb(null); }; @@ -263,6 +263,6 @@ EventSchedulerModule.prototype.shutdown = function(cb) { if(this.eventTimers) { this.eventTimers.forEach( et => et.clear() ); } - + cb(null); }; diff --git a/core/exodus.js b/core/exodus.js index e77183ee..8b3c7548 100644 --- a/core/exodus.js +++ b/core/exodus.js @@ -23,7 +23,7 @@ const SSHClient = require('ssh2').Client; /* Configuration block: - + someDoor: { module: exodus config: { @@ -61,7 +61,7 @@ exports.getModule = class ExodusModule extends MenuModule { this.config = options.menuConfig.config || {}; this.config.ticketHost = this.config.ticketHost || 'oddnetwork.org'; this.config.ticketPort = this.config.ticketPort || 1984, - this.config.ticketPath = this.config.ticketPath || '/exodus'; + this.config.ticketPath = this.config.ticketPath || '/exodus'; this.config.rejectUnauthorized = _.get(this.config, 'rejectUnauthorized', true); this.config.sshHost = this.config.sshHost || this.config.ticketHost; this.config.sshPort = this.config.sshPort || 22; diff --git a/core/file_area_filter_edit.js b/core/file_area_filter_edit.js index 4a53096c..cc4c22c7 100644 --- a/core/file_area_filter_edit.js +++ b/core/file_area_filter_edit.js @@ -65,7 +65,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule { prevFilter : (formData, extraArgs, cb) => { this.currentFilterIndex -= 1; if(this.currentFilterIndex < 0) { - this.currentFilterIndex = this.filtersArray.length - 1; + this.currentFilterIndex = this.filtersArray.length - 1; } this.loadDataForFilter(this.currentFilterIndex); return cb(null); @@ -116,21 +116,21 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule { if(newActive) { filters.setActive(newActive.uuid); } else { - // nothing to set active to + // nothing to set active to this.client.user.removeProperty('file_base_filter_active_uuid'); } } // update UI this.updateActiveLabel(); - + if(this.filtersArray.length > 0) { this.loadDataForFilter(this.currentFilterIndex); } else { this.clearForm(); } return cb(null); - }); + }); }, viewValidationListener : (err, cb) => { @@ -161,7 +161,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule { } } } - + mciReady(mciData, cb) { super.mciReady(mciData, err => { if(err) { @@ -178,7 +178,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule { }, function populateAreas(callback) { self.availAreas = [ { name : '-ALL-' } ].concat(getSortedAvailableFileAreas(self.client) || []); - + const areasView = vc.getView(MciViewIds.editor.area); if(areasView) { areasView.setItems( self.availAreas.map( a => a.name ) ); @@ -194,7 +194,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule { return cb(err); } ); - }); + }); } getCurrentFilter() { @@ -212,7 +212,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule { const activeFilter = FileBaseFilters.getActiveFilter(this.client); if(activeFilter) { const activeFormat = this.menuConfig.config.activeFormat || '{name}'; - this.setText(MciViewIds.editor.activeFilterInfo, stringFormat(activeFormat, activeFilter)); + this.setText(MciViewIds.editor.activeFilterInfo, stringFormat(activeFormat, activeFilter)); } } @@ -256,7 +256,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule { setAreaIndexFromCurrentFilter() { let index; - const filter = this.getCurrentFilter(); + const filter = this.getCurrentFilter(); if(filter) { // special treatment: areaTag saved as blank ("") if -ALL- index = (filter.areaTag && this.availAreas.findIndex(area => filter.areaTag === area.areaTag)) || 0; @@ -295,7 +295,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule { setFilterValuesFromFormData(filter, formData) { filter.name = formData.value.name; filter.areaTag = this.getSelectedAreaTag(formData.value.areaIndex); - filter.terms = formData.value.searchTerms; + filter.terms = formData.value.searchTerms; filter.tags = formData.value.tags; filter.order = this.getOrderBy(formData.value.orderByIndex); filter.sort = this.getSortBy(formData.value.sortByIndex); @@ -304,7 +304,7 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule { saveCurrentFilter(formData, cb) { const filters = new FileBaseFilters(this.client); const selectedFilter = this.filtersArray[this.currentFilterIndex]; - + if(selectedFilter) { // *update* currently selected filter this.setFilterValuesFromFormData(selectedFilter, formData); @@ -316,11 +316,11 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule { // set current to what we just saved newFilter.uuid = filters.add(newFilter); - + // add to our array (at current index position) this.filtersArray[this.currentFilterIndex] = newFilter; } - + return filters.persist(cb); } @@ -334,6 +334,6 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule { this.setAreaIndexFromCurrentFilter(); this.setSortByFromCurrentFilter(); this.setOrderByFromCurrentFilter(); - } + } } }; diff --git a/core/file_area_list.js b/core/file_area_list.js index 3bcfd7c2..87e794cb 100644 --- a/core/file_area_list.js +++ b/core/file_area_list.js @@ -96,7 +96,7 @@ exports.getModule = class FileAreaList extends MenuModule { } this.menuMethods = { - nextFile : (formData, extraArgs, cb) => { + nextFile : (formData, extraArgs, cb) => { if(this.fileListPosition + 1 < this.fileList.length) { this.fileListPosition += 1; @@ -131,7 +131,7 @@ exports.getModule = class FileAreaList extends MenuModule { toggleQueue : (formData, extraArgs, cb) => { this.dlQueue.toggle(this.currentFileEntry); this.updateQueueIndicator(); - return cb(null); + return cb(null); }, showWebDownloadLink : (formData, extraArgs, cb) => { return this.fetchAndDisplayWebDownloadLink(cb); @@ -217,7 +217,7 @@ exports.getModule = class FileAreaList extends MenuModule { const hashTagsSep = config.hashTagsSep || ', '; const isQueuedIndicator = config.isQueuedIndicator || 'Y'; const isNotQueuedIndicator = config.isNotQueuedIndicator || 'N'; - + const entryInfo = currEntry.entryInfo = { fileId : currEntry.fileId, areaTag : currEntry.areaTag, @@ -232,7 +232,7 @@ exports.getModule = class FileAreaList extends MenuModule { hashTags : Array.from(currEntry.hashTags).join(hashTagsSep), isQueued : this.dlQueue.isQueued(currEntry) ? isQueuedIndicator : isNotQueuedIndicator, webDlLink : '', // :TODO: fetch web any existing web d/l link - webDlExpire : '', // :TODO: fetch web d/l link expire time + webDlExpire : '', // :TODO: fetch web d/l link expire time }; // @@ -257,7 +257,7 @@ exports.getModule = class FileAreaList extends MenuModule { // create a rating string, e.g. "**---" const userRatingTicked = config.userRatingTicked || '*'; - const userRatingUnticked = config.userRatingUnticked || ''; + const userRatingUnticked = config.userRatingUnticked || ''; entryInfo.userRating = ~~Math.round(entryInfo.userRating) || 0; // be safe! entryInfo.userRatingString = userRatingTicked.repeat(entryInfo.userRating); if(entryInfo.userRating < 5) { @@ -270,7 +270,7 @@ exports.getModule = class FileAreaList extends MenuModule { if(ErrNotEnabled === err.reasonCode) { entryInfo.webDlExpire = config.webDlLinkNoWebserver || 'Web server is not enabled'; } else { - entryInfo.webDlLink = config.webDlLinkNeedsGenerated || 'Not yet generated'; + entryInfo.webDlLink = config.webDlLinkNeedsGenerated || 'Not yet generated'; } } else { const webDlExpireTimeFormat = config.webDlExpireTimeFormat || 'YYYY-MMM-DD @ h:mm'; @@ -339,10 +339,10 @@ exports.getModule = class FileAreaList extends MenuModule { return vc.loadFromMenuConfig(loadOpts, callback); } - + self.viewControllers[name].setFocus(true); return callback(null); - + }, ], err => { @@ -357,7 +357,7 @@ exports.getModule = class FileAreaList extends MenuModule { async.series( [ function fetchEntryData(callback) { - if(self.fileList) { + if(self.fileList) { return callback(null); } return self.loadFileIds(false, callback); // false=do not force @@ -371,14 +371,14 @@ exports.getModule = class FileAreaList extends MenuModule { function prepArtAndViewController(callback) { return self.displayArtAndPrepViewController('browse', { clearScreen : clearScreen }, callback); }, - function loadCurrentFileInfo(callback) { + function loadCurrentFileInfo(callback) { self.currentFileEntry = new FileEntry(); self.currentFileEntry.load( self.fileList[ self.fileListPosition ], err => { if(err) { return callback(err); } - + return self.populateCurrentEntryInfo(callback); }); }, @@ -422,7 +422,7 @@ exports.getModule = class FileAreaList extends MenuModule { return callback(null); } ], - err => { + err => { if(cb) { return cb(err); } @@ -448,7 +448,7 @@ exports.getModule = class FileAreaList extends MenuModule { function listenNavChanges(callback) { const navMenu = self.viewControllers.details.getView(MciViewIds.details.navMenu); navMenu.setFocusItemIndex(0); - + navMenu.on('index update', index => { const sectionName = { 0 : 'general', @@ -481,7 +481,7 @@ exports.getModule = class FileAreaList extends MenuModule { } ); } - + fetchAndDisplayWebDownloadLink(cb) { const self = this; @@ -492,11 +492,11 @@ exports.getModule = class FileAreaList extends MenuModule { if(self.currentFileEntry.webDlExpireTime < moment()) { return callback(null); } - + const expireTime = moment().add(Config.fileBase.web.expireMinutes, 'minutes'); FileAreaWeb.createAndServeTempDownload( - self.client, + self.client, self.currentFileEntry, { expireTime : expireTime }, (err, url) => { @@ -517,8 +517,8 @@ exports.getModule = class FileAreaList extends MenuModule { }, function updateActiveViews(callback) { self.updateCustomViewTextsWithFilter( - 'browse', - MciViewIds.browse.customRangeStart, self.currentFileEntry.entryInfo, + 'browse', + MciViewIds.browse.customRangeStart, self.currentFileEntry.entryInfo, { filter : [ '{webDlLink}', '{webDlExpire}' ] } ); return callback(null); @@ -527,7 +527,7 @@ exports.getModule = class FileAreaList extends MenuModule { err => { return cb(err); } - ); + ); } updateQueueIndicator() { @@ -535,8 +535,8 @@ exports.getModule = class FileAreaList extends MenuModule { const isNotQueuedIndicator = this.menuConfig.config.isNotQueuedIndicator || 'N'; this.currentFileEntry.entryInfo.isQueued = stringFormat( - this.dlQueue.isQueued(this.currentFileEntry) ? - isQueuedIndicator : + this.dlQueue.isQueued(this.currentFileEntry) ? + isQueuedIndicator : isNotQueuedIndicator ); @@ -558,7 +558,7 @@ exports.getModule = class FileAreaList extends MenuModule { if(!areaInfo) { return cb(Errors.Invalid('Invalid area tag')); } - + const filePath = this.currentFileEntry.filePath; const archiveUtil = ArchiveUtil.getInstance(); @@ -574,7 +574,7 @@ exports.getModule = class FileAreaList extends MenuModule { populateFileListing() { const fileListView = this.viewControllers.detailsFileList.getView(MciViewIds.detailsFileList.fileList); - + if(this.currentFileEntry.entryInfo.archiveType) { this.cacheArchiveEntries( (err, cacheStatus) => { if(err) { @@ -586,7 +586,7 @@ exports.getModule = class FileAreaList extends MenuModule { if('re-cached' === cacheStatus) { const fileListEntryFormat = this.menuConfig.config.fileListEntryFormat || '{fileName} {fileSize}'; // :TODO: use byteSize here? const focusFileListEntryFormat = this.menuConfig.config.focusFileListEntryFormat || fileListEntryFormat; - + fileListView.setItems( this.currentFileEntry.archiveEntries.map( entry => stringFormat(fileListEntryFormat, entry) ) ); fileListView.setFocusItems( this.currentFileEntry.archiveEntries.map( entry => stringFormat(focusFileListEntryFormat, entry) ) ); @@ -594,7 +594,7 @@ exports.getModule = class FileAreaList extends MenuModule { } }); } else { - fileListView.setItems( [ stringFormat(this.menuConfig.config.notAnArchiveFormat || 'Not an archive', { fileName : this.currentFileEntry.fileName } ) ] ); + fileListView.setItems( [ stringFormat(this.menuConfig.config.notAnArchiveFormat || 'Not an archive', { fileName : this.currentFileEntry.fileName } ) ] ); } } @@ -608,7 +608,7 @@ exports.getModule = class FileAreaList extends MenuModule { if(self.lastDetailsViewController) { self.lastDetailsViewController.detachClientEvents(); } - return callback(null); + return callback(null); }, function prepArtAndViewController(callback) { @@ -616,7 +616,7 @@ exports.getModule = class FileAreaList extends MenuModule { self.client.term.rawWrite(ansi.goto(self.detailsInfoArea.top[0], 1)); } - gotoTopPos(); + gotoTopPos(); if(clearArea) { self.client.term.rawWrite(ansi.reset()); diff --git a/core/file_area_web.js b/core/file_area_web.js index b12f4f7d..b8a630fc 100644 --- a/core/file_area_web.js +++ b/core/file_area_web.js @@ -59,7 +59,7 @@ class FileAreaWebAccess { return callback(null); // not enabled, but no error } } - ], + ], err => { return cb(err); } @@ -193,7 +193,7 @@ class FileAreaWebAccess { getExistingTempDownloadServeItem(client, fileEntry, cb) { if(!this.isEnabled()) { return cb(notEnabledError()); - } + } const hashId = this.getSingleFileHashId(client, fileEntry); this.loadServedHashId(hashId, (err, servedItem) => { @@ -201,10 +201,10 @@ class FileAreaWebAccess { return cb(err); } - servedItem.url = this.buildSingleFileTempDownloadLink(client, fileEntry); + servedItem.url = this.buildSingleFileTempDownloadLink(client, fileEntry); return cb(null, servedItem); - }); + }); } _addOrUpdateHashIdRecord(dbOrTrans, hashId, expireTime, cb) { @@ -219,7 +219,7 @@ class FileAreaWebAccess { } this.scheduleExpire(hashId, expireTime); - + return cb(null); } ); @@ -476,7 +476,7 @@ class FileAreaWebAccess { StatLog.incrementUserStat(user, 'dl_total_bytes', dlBytes); StatLog.incrementSystemStat('dl_total_count', 1); StatLog.incrementSystemStat('dl_total_bytes', dlBytes); - + return callback(null); } ], diff --git a/core/file_base_area.js b/core/file_base_area.js index f3845cc1..6c7318d6 100644 --- a/core/file_base_area.js +++ b/core/file_base_area.js @@ -61,8 +61,8 @@ function getAvailableFileAreas(client, options) { // perform ACS check per conf & omit internal if desired const allAreas = _.map(Config.fileBase.areas, (areaInfo, areaTag) => Object.assign(areaInfo, { areaTag : areaTag } )); - - return _.omitBy(allAreas, areaInfo => { + + return _.omitBy(allAreas, areaInfo => { if(!options.includeSystemInternal && isInternalArea(areaInfo.areaTag)) { return true; } @@ -102,7 +102,7 @@ function getDefaultFileAreaTag(client, disableAcsCheck) { defaultArea = _.findKey(Config.fileBase.areas, (area, areaTag) => { return WellKnownAreaTags.MessageAreaAttach !== areaTag && (true === disableAcsCheck || client.acs.hasFileAreaRead(area)); }); - + return defaultArea; } @@ -110,7 +110,7 @@ function getFileAreaByTag(areaTag) { const areaInfo = Config.fileBase.areas[areaTag]; if(areaInfo) { areaInfo.areaTag = areaTag; // convienence! - areaInfo.storage = getAreaStorageLocations(areaInfo); + areaInfo.storage = getAreaStorageLocations(areaInfo); return areaInfo; } } @@ -165,13 +165,13 @@ function getAreaDefaultStorageDirectory(areaInfo) { } function getAreaStorageLocations(areaInfo) { - - const storageTags = Array.isArray(areaInfo.storageTags) ? - areaInfo.storageTags : + + const storageTags = Array.isArray(areaInfo.storageTags) ? + areaInfo.storageTags : [ areaInfo.storageTags || '' ]; const avail = Config.fileBase.storageTags; - + return _.compact(storageTags.map(storageTag => { if(avail[storageTag]) { return { @@ -230,7 +230,7 @@ function attemptSetEstimatedReleaseDate(fileEntry) { const patterns = Config.fileBase.yearEstPatterns.map( p => new RegExp(p, 'gmi')); function getMatch(input) { - if(input) { + if(input) { let m; for(let i = 0; i < patterns.length; ++i) { m = patterns[i].exec(input); @@ -249,7 +249,7 @@ function attemptSetEstimatedReleaseDate(fileEntry) { // const maxYear = moment().add(2, 'year').year(); const match = getMatch(fileEntry.desc) || getMatch(fileEntry.descLong); - + if(match && match[1]) { let year; if(2 === match[1].length) { @@ -316,7 +316,7 @@ function extractAndProcessDescFiles(fileEntry, filePath, archiveEntries, cb) { archiveUtil.extractTo(filePath, tempDir, fileEntry.meta.archive_type, extractList, err => { if(err) { return callback(err); - } + } const descFiles = { desc : shortDescFile ? paths.join(tempDir, shortDescFile.fileName) : null, @@ -327,7 +327,7 @@ function extractAndProcessDescFiles(fileEntry, filePath, archiveEntries, cb) { }); }); }, - function readDescFiles(descFiles, callback) { + function readDescFiles(descFiles, callback) { async.each(Object.keys(descFiles), (descType, next) => { const path = descFiles[descType]; if(!path) { @@ -341,7 +341,7 @@ function extractAndProcessDescFiles(fileEntry, filePath, archiveEntries, cb) { // skip entries that are too large const maxFileSizeKey = `max${_.upperFirst(descType)}FileByteSize`; - + if(Config.fileBase[maxFileSizeKey] && stats.size > Config.fileBase[maxFileSizeKey]) { logDebug( { byteSize : stats.size, maxByteSize : Config.fileBase[maxFileSizeKey] }, `Skipping "${descType}"; Too large` ); return next(null); @@ -353,7 +353,7 @@ function extractAndProcessDescFiles(fileEntry, filePath, archiveEntries, cb) { } // - // Assume FILE_ID.DIZ, NFO files, etc. are CP437. + // Assume FILE_ID.DIZ, NFO files, etc. are CP437. // // :TODO: This isn't really always the case - how to handle this? We could do a quick detection... fileEntry[descType] = iconv.decode(sliceAtSauceMarker(data, 0x1a), 'cp437'); @@ -389,10 +389,10 @@ function extractAndProcessSingleArchiveEntry(fileEntry, filePath, archiveEntries } const archiveUtil = ArchiveUtil.getInstance(); - + // ensure we only extract one - there should only be one anyway -- we also just need the fileName const extractList = archiveEntries.slice(0, 1).map(entry => entry.fileName); - + archiveUtil.extractTo(filePath, tempDir, fileEntry.meta.archive_type, extractList, err => { if(err) { return callback(err); @@ -540,7 +540,7 @@ function populateFileEntryInfoFromFile(fileEntry, filePath, cb) { }); }, () => { return cb(null); - }); + }); } function populateFileEntryNonArchive(fileEntry, filePath, stepInfo, iterator, cb) { @@ -586,10 +586,6 @@ function addNewFileEntry(fileEntry, filePath, cb) { ); } -function updateFileEntry(fileEntry, filePath, cb) { - -} - const HASH_NAMES = [ 'sha1', 'sha256', 'md5', 'crc32' ]; function scanFile(filePath, options, iterator, cb) { @@ -664,7 +660,7 @@ function scanFile(filePath, options, iterator, cb) { return callIter(callback); }); }, - function processPhysicalFileGeneric(callback) { + function processPhysicalFileGeneric(callback) { stepInfo.bytesProcessed = 0; const hashes = {}; @@ -690,7 +686,7 @@ function scanFile(filePath, options, iterator, cb) { stream.on('data', data => { stream.pause(); // until iterator compeltes - stepInfo.bytesProcessed += data.length; + stepInfo.bytesProcessed += data.length; stepInfo.calcHashPercent = Math.round(((stepInfo.bytesProcessed / stepInfo.byteSize) * 100)); // @@ -710,13 +706,13 @@ function scanFile(filePath, options, iterator, cb) { updateHashes(data); }); - } + } }); stream.on('end', () => { fileEntry.meta.byte_size = stepInfo.bytesProcessed; - async.each(hashesToCalc, (hashName, nextHash) => { + async.each(hashesToCalc, (hashName, nextHash) => { if('sha256' === hashName) { stepInfo.sha256 = fileEntry.fileSha256 = hashes.sha256.digest('hex'); } else if('sha1' === hashName || 'md5' === hashName) { @@ -747,7 +743,9 @@ function scanFile(filePath, options, iterator, cb) { populateFileEntryWithArchive(fileEntry, filePath, stepInfo, callIter, err => { if(err) { populateFileEntryNonArchive(fileEntry, filePath, stepInfo, callIter, err => { - // :TODO: log err + if(err) { + logDebug( { error : err.message }, 'Non-archive file entry population failed'); + } return callback(null); // ignore err }); } else { @@ -756,7 +754,9 @@ function scanFile(filePath, options, iterator, cb) { }); } else { populateFileEntryNonArchive(fileEntry, filePath, stepInfo, callIter, err => { - // :TODO: log err + if(err) { + logDebug( { error : err.message }, 'Non-archive file entry population failed'); + } return callback(null); // ignore err }); } @@ -773,7 +773,7 @@ function scanFile(filePath, options, iterator, cb) { return callback(null, dupeEntries); }); } - ], + ], (err, dupeEntries) => { if(err) { return cb(err); @@ -858,12 +858,12 @@ function scanFileAreaForChanges(areaInfo, options, iterator, cb) { // :TODO: Look @ db entries for area that were *not* processed above return callback(null); } - ], + ], err => { return nextLocation(err); } ); - }, + }, err => { return cb(err); }); @@ -874,14 +874,14 @@ function getDescFromFileName(fileName) { const ext = paths.extname(fileName); const name = paths.basename(fileName, ext); - return _.upperFirst(name.replace(/[\-_.+]/g, ' ').replace(/\s+/g, ' ')); + return _.upperFirst(name.replace(/[-_.+]/g, ' ').replace(/\s+/g, ' ')); } // // Return an object of stats about an area(s) // // { -// +// // totalFiles : , // totalBytes : , // areas : { @@ -892,7 +892,7 @@ function getDescFromFileName(fileName) { // } // } // -function getAreaStats(cb) { +function getAreaStats(cb) { FileDb.all( `SELECT DISTINCT f.area_tag, COUNT(f.file_id) AS total_files, SUM(m.meta_value) AS total_byte_size FROM file f, file_meta m @@ -928,9 +928,9 @@ function getAreaStats(cb) { // method exposed for event scheduler function updateAreaStatsScheduledEvent(args, cb) { - getAreaStats( (err, stats) => { + getAreaStats( (err, stats) => { if(!err) { - StatLog.setNonPeristentSystemStat('file_base_area_stats', stats); + StatLog.setNonPeristentSystemStat('file_base_area_stats', stats); } return cb(err); diff --git a/core/file_base_area_select.js b/core/file_base_area_select.js index 5ec266fd..87dfe9f4 100644 --- a/core/file_base_area_select.js +++ b/core/file_base_area_select.js @@ -38,7 +38,7 @@ exports.getModule = class FileAreaSelectModule extends MenuModule { const menuOpts = { extraArgs : { - filterCriteria : filterCriteria, + filterCriteria : filterCriteria, }, menuFlags : [ 'popParent' ], }; diff --git a/core/file_base_download_manager.js b/core/file_base_download_manager.js index 7444af56..88ed2ddd 100644 --- a/core/file_base_download_manager.js +++ b/core/file_base_download_manager.js @@ -59,8 +59,6 @@ exports.getModule = class FileBaseDownloadQueueManager extends MenuModule { return this.gotoMenu(this.menuConfig.config.fileTransferProtocolSelection || 'fileTransferProtocolSelection', modOpts, cb); }, - viewItemInfo : (formData, extraArgs, cb) => { - }, removeItem : (formData, extraArgs, cb) => { const selectedItem = this.dlQueue.items[formData.value.queueItem]; if(!selectedItem) { @@ -74,7 +72,7 @@ exports.getModule = class FileBaseDownloadQueueManager extends MenuModule { }, clearQueue : (formData, extraArgs, cb) => { this.dlQueue.clear(); - + // :TODO: broken: does not redraw menu properly - needs fixed! return this.removeItemsFromDownloadQueueView('all', cb); } @@ -230,10 +228,10 @@ exports.getModule = class FileBaseDownloadQueueManager extends MenuModule { return vc.loadFromMenuConfig(loadOpts, callback); } - + self.viewControllers[name].setFocus(true); return callback(null); - + }, ], err => { diff --git a/core/file_base_filter.js b/core/file_base_filter.js index 320d36d3..d8b566b7 100644 --- a/core/file_base_filter.js +++ b/core/file_base_filter.js @@ -8,7 +8,7 @@ const uuidV4 = require('uuid/v4'); module.exports = class FileBaseFilters { constructor(client) { this.client = client; - + this.load(); } @@ -25,7 +25,7 @@ module.exports = class FileBaseFilters { 'est_release_year', 'byte_size', 'file_name', - ]; + ]; } toArray() { @@ -40,11 +40,11 @@ module.exports = class FileBaseFilters { add(filterInfo) { const filterUuid = uuidV4(); - + filterInfo.tags = this.cleanTags(filterInfo.tags); - + this.filters[filterUuid] = filterInfo; - + return filterUuid; } @@ -94,18 +94,18 @@ module.exports = class FileBaseFilters { } cleanTags(tags) { - return tags.toLowerCase().replace(/,?\s+|\,/g, ' ').trim(); + return tags.toLowerCase().replace(/,?\s+|,/g, ' ').trim(); } setActive(filterUuid) { const activeFilter = this.get(filterUuid); - + if(activeFilter) { this.activeFilter = activeFilter; this.client.user.persistProperty('file_base_filter_active_uuid', filterUuid); return true; } - + return false; } diff --git a/core/file_base_search.js b/core/file_base_search.js index 27656123..06dac204 100644 --- a/core/file_base_search.js +++ b/core/file_base_search.js @@ -110,7 +110,7 @@ exports.getModule = class FileBaseSearch extends MenuModule { const menuOpts = { extraArgs : { - filterCriteria : filterCriteria, + filterCriteria : filterCriteria, }, menuFlags : [ 'popParent' ], }; diff --git a/core/file_base_web_download_manager.js b/core/file_base_web_download_manager.js index dea7c5a8..13b7de33 100644 --- a/core/file_base_web_download_manager.js +++ b/core/file_base_web_download_manager.js @@ -32,13 +32,13 @@ const MciViewIds = { queueManager : { queue : 1, navMenu : 2, - + customRangeStart : 10, } }; exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule { - + constructor(options) { super(options); @@ -58,7 +58,7 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule { }, clearQueue : (formData, extraArgs, cb) => { this.dlQueue.clear(); - + // :TODO: broken: does not redraw menu properly - needs fixed! return this.removeItemsFromDownloadQueueView('all', cb); }, @@ -109,7 +109,7 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule { displayFileInfoForFileEntry(fileEntry) { this.updateCustomViewTextsWithFilter( - 'queueManager', + 'queueManager', MciViewIds.queueManager.customRangeStart, fileEntry, { filter : [ '{webDlLink}', '{webDlExpire}', '{fileName}' ] } // :TODO: Others.... ); @@ -142,7 +142,7 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule { const expireTime = moment().add(Config.fileBase.web.expireMinutes, 'minutes'); FileAreaWeb.createAndServeTempBatchDownload( - this.client, + this.client, this.dlQueue.items, { expireTime : expireTime @@ -162,7 +162,7 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule { this.updateCustomViewTextsWithFilter( 'queueManager', - MciViewIds.queueManager.customRangeStart, + MciViewIds.queueManager.customRangeStart, formatObj, { filter : Object.keys(formatObj).map(k => '{' + k + '}' ) } ); @@ -187,13 +187,13 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule { FileAreaWeb.getExistingTempDownloadServeItem(self.client, fileEntry, (err, serveItem) => { if(err) { if(ErrNotEnabled === err.reasonCode) { - return nextFileEntry(err); // we should have caught this prior + return nextFileEntry(err); // we should have caught this prior } const expireTime = moment().add(Config.fileBase.web.expireMinutes, 'minutes'); - + FileAreaWeb.createAndServeTempDownload( - self.client, + self.client, fileEntry, { expireTime : expireTime }, (err, url) => { @@ -202,13 +202,13 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule { } fileEntry.webDlLinkRaw = url; - fileEntry.webDlLink = ansi.vtxHyperlink(self.client, url) + url; + fileEntry.webDlLink = ansi.vtxHyperlink(self.client, url) + url; fileEntry.webDlExpire = expireTime.format(webDlExpireTimeFormat); return nextFileEntry(null); } ); - } else { + } else { fileEntry.webDlLinkRaw = serveItem.url; fileEntry.webDlLink = ansi.vtxHyperlink(self.client, serveItem.url) + serveItem.url; fileEntry.webDlExpire = moment(serveItem.expireTimestamp).format(webDlExpireTimeFormat); @@ -272,10 +272,10 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule { return vc.loadFromMenuConfig(loadOpts, callback); } - + self.viewControllers[name].setFocus(true); return callback(null); - + }, ], err => { @@ -284,4 +284,3 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule { ); } }; - \ No newline at end of file diff --git a/core/file_entry.js b/core/file_entry.js index 8bf7a69d..861b9d79 100644 --- a/core/file_entry.js +++ b/core/file_entry.js @@ -15,7 +15,7 @@ const { unlink, readFile } = require('graceful-fs'); const crypto = require('crypto'); const moment = require('moment'); -const FILE_TABLE_MEMBERS = [ +const FILE_TABLE_MEMBERS = [ 'file_id', 'area_tag', 'file_sha256', 'file_name', 'storage_tag', 'desc', 'desc_long', 'upload_timestamp' ]; @@ -47,7 +47,7 @@ module.exports = class FileEntry { // values we always want dl_count : 0, }; - + this.hashTags = options.hashTags || new Set(); this.fileName = options.fileName; this.storageTag = options.storageTag; @@ -173,7 +173,7 @@ module.exports = class FileEntry { async.each(Object.keys(self.meta), (n, next) => { const v = self.meta[n]; return FileEntry.persistMetaValue(self.fileId, n, v, trans, next); - }, + }, err => { return callback(err, trans); }); @@ -185,7 +185,7 @@ module.exports = class FileEntry { }, err => { return callback(err, trans); - }); + }); } ], (err, trans) => { @@ -203,10 +203,10 @@ module.exports = class FileEntry { static getAreaStorageDirectoryByTag(storageTag) { const storageLocation = (storageTag && Config.fileBase.storageTags[storageTag]); - + // absolute paths as-is if(storageLocation && '/' === storageLocation.charAt(0)) { - return storageLocation; + return storageLocation; } // relative to |areaStoragePrefix| @@ -283,7 +283,7 @@ module.exports = class FileEntry { transOrDb.serialize( () => { transOrDb.run( `INSERT OR IGNORE INTO hash_tag (hash_tag) - VALUES (?);`, + VALUES (?);`, [ hashTag ] ); @@ -321,7 +321,7 @@ module.exports = class FileEntry { err => { return cb(err); } - ); + ); } loadRating(cb) { @@ -352,7 +352,7 @@ module.exports = class FileEntry { } static get WellKnownMetaValues() { - return Object.keys(FILE_WELL_KNOWN_META); + return Object.keys(FILE_WELL_KNOWN_META); } static findFileBySha(sha, cb) { @@ -469,7 +469,7 @@ module.exports = class FileEntry { sqlOrderBy = `ORDER BY avg_rating ${sqlOrderDir}`; } else { - sql = + sql = `SELECT DISTINCT f.file_id, f.${filter.sort} FROM file f`; @@ -531,7 +531,7 @@ module.exports = class FileEntry { )` ); } - + if(filter.tags && filter.tags.length > 0) { // build list of quoted tags; filter.tags comes in as a space and/or comma separated values const tags = filter.tags.replace(/,/g, ' ').replace(/\s{2,}/g, ' ').split(' ').map( tag => `"${tag}"` ).join(','); @@ -617,7 +617,7 @@ module.exports = class FileEntry { const srcPath = srcFileEntry.filePath; const dstDir = FileEntry.getAreaStorageDirectoryByTag(destStorageTag); - + if(!dstDir) { return cb(Errors.Invalid('Invalid storage tag')); } diff --git a/core/file_transfer.js b/core/file_transfer.js index 4e81bf72..bb3d362c 100644 --- a/core/file_transfer.js +++ b/core/file_transfer.js @@ -65,7 +65,7 @@ exports.getModule = class TransferFileModule extends MenuModule { } if(options.extraArgs.sendQueue) { - this.sendQueue = options.extraArgs.sendQueue; + this.sendQueue = options.extraArgs.sendQueue; } if(options.extraArgs.recvFileName) { @@ -107,7 +107,7 @@ exports.getModule = class TransferFileModule extends MenuModule { return { path : item }; } else { return item; - } + } }); this.sentFileIds = []; @@ -137,7 +137,7 @@ exports.getModule = class TransferFileModule extends MenuModule { this.sendQueue.forEach(f => { f.sent = true; sentFiles.push(f.path); - + }); this.client.log.info( { sentFiles : sentFiles }, `Successfully sent ${sentFiles.length} file(s)` ); @@ -160,7 +160,7 @@ exports.getModule = class TransferFileModule extends MenuModule { this.sendQueue.forEach(f => { f.sent = true; sentFiles.push(f.path); - + }); this.client.log.info( { sentFiles : sentFiles }, `Successfully sent ${sentFiles.length} file(s)` ); @@ -180,16 +180,16 @@ exports.getModule = class TransferFileModule extends MenuModule { } return next(err); }); - }, err => { + }, err => { return cb(err); }); - } + } } */ moveFileWithCollisionHandling(src, dst, cb) { // - // Move |src| -> |dst| renaming to file(1).ext, file(2).ext, etc. + // Move |src| -> |dst| renaming to file(1).ext, file(2).ext, etc. // in the case of collisions. // const dstPath = paths.dirname(dst); @@ -283,7 +283,7 @@ exports.getModule = class TransferFileModule extends MenuModule { }); }, () => { return cb(null); - }); + }); }); } }); @@ -309,7 +309,7 @@ exports.getModule = class TransferFileModule extends MenuModule { temptmp.open( { prefix : TEMP_SUFFIX, suffix : '.txt' }, (err, tempFileInfo) => { if(err) { - return callback(err); // failed to create it + return callback(err); // failed to create it } fs.write(tempFileInfo.fd, filePaths.join(SYSTEM_EOL)); @@ -334,7 +334,7 @@ exports.getModule = class TransferFileModule extends MenuModule { return callback(null, args); } - ], + ], (err, args) => { return cb(err, args); } @@ -364,7 +364,7 @@ exports.getModule = class TransferFileModule extends MenuModule { const externalProc = pty.spawn(cmd, args, { cols : this.client.term.termWidth, rows : this.client.term.termHeight, - cwd : this.recvDirectory, + cwd : this.recvDirectory, }); this.client.setTemporaryDirectDataHandler(data => { @@ -376,7 +376,7 @@ exports.getModule = class TransferFileModule extends MenuModule { externalProc.write(data); } }); - + externalProc.on('data', data => { // needed for things like sz/rz if(external.escapeTelnet) { @@ -393,12 +393,12 @@ exports.getModule = class TransferFileModule extends MenuModule { externalProc.once('exit', (exitCode) => { this.client.log.debug( { cmd : cmd, args : args, exitCode : exitCode }, 'Process exited' ); - + this.restorePipeAfterExternalProc(); externalProc.removeAllListeners(); return cb(exitCode ? Errors.ExternalProcess(`Process exited with exit code ${exitCode}`, 'EBADEXIT') : null); - }); + }); } executeExternalProtocolHandlerForSend(filePaths, cb) { @@ -413,7 +413,7 @@ exports.getModule = class TransferFileModule extends MenuModule { this.executeExternalProtocolHandler(args, err => { return cb(err); - }); + }); }); } @@ -434,7 +434,7 @@ exports.getModule = class TransferFileModule extends MenuModule { return { sentFileIds : this.sentFileIds }; } else { return { recvFilePaths : this.recvFilePaths }; - } + } } updateSendStats(cb) { @@ -478,11 +478,11 @@ exports.getModule = class TransferFileModule extends MenuModule { fileIds.forEach(fileId => { FileEntry.incrementAndPersistMetaValue(fileId, 'dl_count', 1); }); - + return cb(null); }); } - + updateRecvStats(cb) { let uploadBytes = 0; let uploadCount = 0; @@ -519,7 +519,7 @@ exports.getModule = class TransferFileModule extends MenuModule { function validateConfig(callback) { if(self.isSending()) { if(!Array.isArray(self.sendQueue)) { - self.sendQueue = [ self.sendQueue ]; + self.sendQueue = [ self.sendQueue ]; } } @@ -555,7 +555,7 @@ exports.getModule = class TransferFileModule extends MenuModule { }); } }, - function cleanupTempFiles(callback) { + function cleanupTempFiles(callback) { temptmp.cleanup( paths => { Log.debug( { paths : paths, sessionId : temptmp.sessionId }, 'Temporary files cleaned up' ); }); diff --git a/core/file_transfer_protocol_select.js b/core/file_transfer_protocol_select.js index f1b3dbed..299c8af2 100644 --- a/core/file_transfer_protocol_select.js +++ b/core/file_transfer_protocol_select.js @@ -64,7 +64,7 @@ exports.getModule = class FileTransferProtocolSelectModule extends MenuModule { return this.gotoMenu(this.config.downloadFilesMenu || 'sendFilesToUser', modOpts, cb); } else { return this.gotoMenu(this.config.uploadFilesMenu || 'recvFilesFromUser', modOpts, cb); - } + } }, }; } @@ -118,7 +118,7 @@ exports.getModule = class FileTransferProtocolSelectModule extends MenuModule { protListView.redraw(); - return callback(null); + return callback(null); } ], err => { diff --git a/core/file_util.js b/core/file_util.js index 9452b23f..0f91e71a 100644 --- a/core/file_util.js +++ b/core/file_util.js @@ -66,11 +66,11 @@ function moveOrCopyFileWithCollisionHandling(src, dst, operation, cb) { (err, finalPath) => { return cb(err, finalPath); } - ); + ); } // -// Move |src| -> |dst| renaming to file(1).ext, file(2).ext, etc. +// Move |src| -> |dst| renaming to file(1).ext, file(2).ext, etc. // in the case of collisions. // function moveFileWithCollisionHandling(src, dst, cb) { diff --git a/core/fnv1a.js b/core/fnv1a.js index f7714936..743986d6 100644 --- a/core/fnv1a.js +++ b/core/fnv1a.js @@ -7,7 +7,7 @@ let _ = require('lodash'); module.exports = class FNV1a { constructor(data) { this.hash = 0x811c9dc5; - + if(!_.isUndefined(data)) { this.update(data); } @@ -17,7 +17,7 @@ module.exports = class FNV1a { if(_.isNumber(data)) { data = data.toString(); } - + if(_.isString(data)) { data = new Buffer(data); } @@ -28,8 +28,8 @@ module.exports = class FNV1a { for(let b of data) { this.hash = this.hash ^ b; - this.hash += - (this.hash << 24) + (this.hash << 8) + (this.hash << 7) + + this.hash += + (this.hash << 24) + (this.hash << 8) + (this.hash << 7) + (this.hash << 4) + (this.hash << 1); } @@ -46,5 +46,5 @@ module.exports = class FNV1a { get value() { return this.hash & 0xffffffff; } -} +}; diff --git a/core/fse.js b/core/fse.js index b266a9c9..02134f31 100644 --- a/core/fse.js +++ b/core/fse.js @@ -39,7 +39,7 @@ exports.moduleInfo = { TL2 - To TL3 - Subject TL4 - Area name - + TL5 - Date/Time (TODO: format) TL6 - Message number TL7 - Mesage total (in area) @@ -50,7 +50,7 @@ exports.moduleInfo = { TL12 - User1 TL13 - User2 - + Footer - Viewing HM1 - Menu (prev/next/etc.) @@ -61,14 +61,14 @@ exports.moduleInfo = { TL12 - User1 (fmt message object) TL13 - User2 - + */ const MciCodeIds = { ViewModeHeader : { From : 1, To : 2, Subject : 3, - + DateTime : 5, MsgNum : 6, MsgTotal : 7, @@ -78,9 +78,9 @@ const MciCodeIds = { ReplyToMsgID : 11, // :TODO: ConfName - + }, - + ViewModeFooter : { MsgNum : 6, MsgTotal : 7, @@ -90,7 +90,7 @@ const MciCodeIds = { From : 1, To : 2, Subject : 3, - + ErrorMsg : 13, }, }; @@ -116,12 +116,12 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul // toUserId // this.editorType = config.editorType; - this.editorMode = config.editorMode; - + this.editorMode = config.editorMode; + if(config.messageAreaTag) { this.messageAreaTag = config.messageAreaTag; } - + this.messageIndex = config.messageIndex || 0; this.messageTotal = config.messageTotal || 0; this.toUserId = config.toUserId || 0; @@ -160,7 +160,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul if(errMsgView) { if(err) { errMsgView.setText(err.message); - + if(MciCodeIds.ViewModeHeader.Subject === err.view.getId()) { // :TODO: for "area" mode, should probably just bail if this is emtpy (e.g. cancel) } @@ -179,26 +179,24 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul self.switchFooter(function next(err) { if(err) { - // :TODO:... what now? - console.log(err) - } else { - switch(self.footerMode) { - case 'editor' : - if(!_.isUndefined(self.viewControllers.footerEditorMenu)) { - //self.viewControllers.footerEditorMenu.setFocus(false); - self.viewControllers.footerEditorMenu.detachClientEvents(); - } - self.viewControllers.body.switchFocus(1); - self.observeEditorEvents(); - break; + return cb(err); + } - case 'editorMenu' : - self.viewControllers.body.setFocus(false); - self.viewControllers.footerEditorMenu.switchFocus(1); - break; + switch(self.footerMode) { + case 'editor' : + if(!_.isUndefined(self.viewControllers.footerEditorMenu)) { + self.viewControllers.footerEditorMenu.detachClientEvents(); + } + self.viewControllers.body.switchFocus(1); + self.observeEditorEvents(); + break; - default : throw new Error('Unexpected mode'); - } + case 'editorMenu' : + self.viewControllers.body.setFocus(false); + self.viewControllers.footerEditorMenu.switchFocus(1); + break; + + default : throw new Error('Unexpected mode'); } return cb(null); @@ -210,9 +208,9 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul return cb(null); }, appendQuoteEntry: function(formData, extraArgs, cb) { - // :TODO: Dont' use magic # ID's here + // :TODO: Dont' use magic # ID's here const quoteMsgView = self.viewControllers.quoteBuilder.getView(1); - + if(self.newQuoteBlock) { self.newQuoteBlock = false; @@ -220,7 +218,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul quoteMsgView.addText(self.getQuoteByHeader()); } - + const quoteText = self.viewControllers.quoteBuilder.getView(3).getItem(formData.value.quote); quoteMsgView.addText(quoteText); @@ -339,7 +337,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul // // Ensure first characters indicate ANSI for detection down // the line (other boards/etc.). We also set explicit_encoding - // to packetAnsiMsgEncoding (generally cp437) as various boards + // to packetAnsiMsgEncoding (generally cp437) as various boards // really don't like ANSI messages in UTF-8 encoding (they should!) // msgOpts.meta = { System : { 'explicit_encoding' : Config.scannerTossers.ftn_bso.packetAnsiMsgEncoding || 'cp437' } }; @@ -351,7 +349,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul return cb(null); } - + setMessage(message) { this.message = message; @@ -495,7 +493,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul // :TODO: We'd like to delete up to N rows, but this does not work // in NetRunner: self.client.term.rawWrite(ansi.reset() + ansi.deleteLine(3)); - + self.client.term.rawWrite(ansi.reset() + ansi.eraseLine(2)); } callback(null); @@ -534,7 +532,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul art[n], self.client, { font : self.menuConfig.font }, - function displayed(err, artData) { + function displayed(err) { next(err); } ); @@ -561,7 +559,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul function complete(err) { cb(err); } - ); + ); } switchFooter(cb) { @@ -645,14 +643,13 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul ], function complete(err) { if(err) { - // :TODO: This needs properly handled! - console.log(err) + self.client.log.warn( { error : err.message }, 'FSE init error'); } else { self.isReady = true; self.finishedLoading(); } } - ); + ); } createInitialViews(mciData, cb) { @@ -666,7 +663,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul menuLoadOpts.mciMap = mciData.header.mciMap; self.addViewController( - 'header', + 'header', new ViewController( { client : self.client, formId : menuLoadOpts.formId } ) ).loadFromMenuConfig(menuLoadOpts, function headerReady(err) { callback(err); @@ -713,7 +710,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul }, function setInitialData(callback) { - switch(self.editorMode) { + switch(self.editorMode) { case 'view' : if(self.message) { self.initHeaderViewMode(); @@ -726,7 +723,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul } } break; - + case 'edit' : { const fromView = self.viewControllers.header.getView(1); @@ -747,9 +744,9 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul callback(null); }, function setInitialFocus(callback) { - + switch(self.editorMode) { - case 'edit' : + case 'edit' : self.switchToHeader(); break; @@ -763,10 +760,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul } ], function complete(err) { - if(err) { - console.error(err) - } - cb(err); + return cb(err); } ); } @@ -774,7 +768,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul mciReadyHandler(mciData, cb) { this.createInitialViews(mciData, err => { - // :TODO: Can probably be replaced with @systemMethod:validateUserNameExists when the framework is in + // :TODO: Can probably be replaced with @systemMethod:validateUserNameExists when the framework is in // place - if this is for existing usernames else validate spec /* @@ -787,7 +781,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul view.clearText(); self.viewControllers.headers.switchFocus(2); } - }); + }); } });*/ @@ -813,7 +807,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul if(modeView) { this.client.term.rawWrite(ansi.savePos()); modeView.setText('insert' === mode ? 'INS' : 'OVR'); - this.client.term.rawWrite(ansi.restorePos()); + this.client.term.rawWrite(ansi.restorePos()); } } } @@ -824,7 +818,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul initHeaderViewMode() { assert(_.isObject(this.message)); - + this.setHeaderText(MciCodeIds.ViewModeHeader.From, this.message.fromUserName); this.setHeaderText(MciCodeIds.ViewModeHeader.To, this.message.toUserName); this.setHeaderText(MciCodeIds.ViewModeHeader.Subject, this.message.subject); @@ -881,7 +875,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul // this.newQuoteBlock = true; const self = this; - + async.waterfall( [ function clearAndDisplayArt(callback) { @@ -892,23 +886,23 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul self.client.term.rawWrite( ansi.goto(self.header.height + 1, 1) + ansi.deleteLine(24 - self.header.height)); - + theme.displayThemeArt( { name : self.menuConfig.config.art.quote, client : self.client }, function displayed(err, artData) { callback(err, artData); }); }, function createViewsIfNecessary(artData, callback) { var formId = self.getFormId('quoteBuilder'); - + if(_.isUndefined(self.viewControllers.quoteBuilder)) { var menuLoadOpts = { callingMenu : self, formId : formId, - mciMap : artData.mciMap, + mciMap : artData.mciMap, }; - + self.addViewController( - 'quoteBuilder', + 'quoteBuilder', new ViewController( { client : self.client, formId : formId } ) ).loadFromMenuConfig(menuLoadOpts, function quoteViewsReady(err) { callback(err); @@ -954,10 +948,10 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul ], function complete(err) { if(err) { - console.log(err) // :TODO: needs real impl. + self.client.log.warn( { error : err.message }, 'Error displaying quote builder'); } } - ); + ); } observeEditorEvents() { @@ -1004,22 +998,22 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul var body = this.viewControllers.body.getView(1); body.redraw(); this.viewControllers.body.switchFocus(1); - + // :TODO: create method (DRY) - + this.updateTextEditMode(body.getTextEditMode()); this.updateEditModePosition(body.getEditPosition()); this.observeEditorEvents(); } - + quoteBuilderFinalize() { // :TODO: fix magic #'s const quoteMsgView = this.viewControllers.quoteBuilder.getView(1); const msgView = this.viewControllers.body.getView(1); - + let quoteLines = quoteMsgView.getData().trim(); - + if(quoteLines.length > 0) { if(this.replyIsAnsi) { const bodyMessageView = this.viewControllers.body.getView(1); @@ -1027,7 +1021,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul } msgView.addText(`${quoteLines}\n\n`); } - + quoteMsgView.setText(''); this.footerMode = 'editor'; @@ -1040,14 +1034,14 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul getQuoteByHeader() { let quoteFormat = this.menuConfig.config.quoteFormats; - if(Array.isArray(quoteFormat)) { + if(Array.isArray(quoteFormat)) { quoteFormat = quoteFormat[ Math.floor(Math.random() * quoteFormat.length) ]; } else if(!_.isString(quoteFormat)) { quoteFormat = 'On {dateTime} {userName} said...'; } - const dtFormat = this.menuConfig.config.quoteDateTimeFormat || this.client.currentTheme.helpers.getDateTimeFormat(); - return stringFormat(quoteFormat, { + const dtFormat = this.menuConfig.config.quoteDateTimeFormat || this.client.currentTheme.helpers.getDateTimeFormat(); + return stringFormat(quoteFormat, { dateTime : moment(this.replyToMessage.modTimestamp).format(dtFormat), userName : this.replyToMessage.fromUserName, }); diff --git a/core/ftn_address.js b/core/ftn_address.js index f0936e1d..6b1e57e0 100644 --- a/core/ftn_address.js +++ b/core/ftn_address.js @@ -3,8 +3,8 @@ const _ = require('lodash'); -const FTN_ADDRESS_REGEXP = /^([0-9]+:)?([0-9]+)(\/[0-9]+)?(\.[0-9]+)?(@[a-z0-9\-\.]+)?$/i; -const FTN_PATTERN_REGEXP = /^([0-9\*]+:)?([0-9\*]+)(\/[0-9\*]+)?(\.[0-9\*]+)?(@[a-z0-9\-\.\*]+)?$/i; +const FTN_ADDRESS_REGEXP = /^([0-9]+:)?([0-9]+)(\/[0-9]+)?(\.[0-9]+)?(@[a-z0-9\-.]+)?$/i; +const FTN_PATTERN_REGEXP = /^([0-9*]+:)?([0-9*]+)(\/[0-9*]+)?(\.[0-9*]+)?(@[a-z0-9\-.*]+)?$/i; module.exports = class Address { constructor(addr) { @@ -133,7 +133,7 @@ module.exports = class Address { static fromString(addrStr) { const m = FTN_ADDRESS_REGEXP.exec(addrStr); - + if(m) { // start with a 2D let addr = { @@ -165,7 +165,7 @@ module.exports = class Address { let addrStr = `${this.zone}:${this.net}`; - // allow for e.g. '4D' or 5 + // allow for e.g. '4D' or 5 const dim = parseInt(dimensions.toString()[0]); if(dim >= 3) { diff --git a/core/ftn_mail_packet.js b/core/ftn_mail_packet.js index d84b4a69..d2f003e9 100644 --- a/core/ftn_mail_packet.js +++ b/core/ftn_mail_packet.js @@ -56,7 +56,7 @@ class PacketHeader { this.capWordValidate = ((this.capWord & 0xff) << 8) | ((this.capWord >> 8) & 0xff); // swap this.prodCodeHi = 0xfe; // see above - this.prodRevHi = 0; + this.prodRevHi = 0; } get origAddress() { @@ -84,9 +84,9 @@ class PacketHeader { // See FSC-48 // :TODO: disabled for now until we have separate packet writers for 2, 2+, 2+48, and 2.2 - /*if(address.point) { + /*if(address.point) { this.auxNet = address.origNet; - this.origNet = -1; + this.origNet = -1; } else { this.origNet = address.net; this.auxNet = 0; @@ -158,16 +158,16 @@ exports.PacketHeader = PacketHeader; // // * Type 2 FTS-0001 @ http://ftsc.org/docs/fts-0001.016 (Obsolete) // * Type 2.2 FSC-0045 @ http://ftsc.org/docs/fsc-0045.001 -// * Type 2+ FSC-0039 and FSC-0048 @ http://ftsc.org/docs/fsc-0039.004 +// * Type 2+ FSC-0039 and FSC-0048 @ http://ftsc.org/docs/fsc-0039.004 // and http://ftsc.org/docs/fsc-0048.002 -// +// // Additional resources: // * Writeup on differences between type 2, 2.2, and 2+: // http://walon.org/pub/fidonet/FTSC-nodelists-etc./pkt-types.txt // function Packet(options) { var self = this; - + this.options = options || {}; this.parsePacketHeader = function(packetBuffer, cb) { @@ -240,11 +240,11 @@ function Packet(options) { // // See heuristics described in FSC-0048, "Receiving Type-2+ bundles" // - const capWordValidateSwapped = + const capWordValidateSwapped = ((packetHeader.capWordValidate & 0xff) << 8) | ((packetHeader.capWordValidate >> 8) & 0xff); - if(capWordValidateSwapped === packetHeader.capWord && + if(capWordValidateSwapped === packetHeader.capWord && 0 != packetHeader.capWord && packetHeader.capWord & 0x0001) { @@ -260,7 +260,7 @@ function Packet(options) { // :TODO: should fill bytes be 0? } } - + packetHeader.created = moment({ year : packetHeader.year, month : packetHeader.month - 1, // moment uses 0 indexed months @@ -269,36 +269,36 @@ function Packet(options) { minute : packetHeader.minute, second : packetHeader.second }); - + let ph = new PacketHeader(); _.assign(ph, packetHeader); cb(null, ph); }); }; - + this.getPacketHeaderBuffer = function(packetHeader) { let buffer = new Buffer(FTN_PACKET_HEADER_SIZE); buffer.writeUInt16LE(packetHeader.origNode, 0); buffer.writeUInt16LE(packetHeader.destNode, 2); buffer.writeUInt16LE(packetHeader.year, 4); - buffer.writeUInt16LE(packetHeader.month, 6); + buffer.writeUInt16LE(packetHeader.month, 6); buffer.writeUInt16LE(packetHeader.day, 8); buffer.writeUInt16LE(packetHeader.hour, 10); buffer.writeUInt16LE(packetHeader.minute, 12); buffer.writeUInt16LE(packetHeader.second, 14); - + buffer.writeUInt16LE(packetHeader.baud, 16); buffer.writeUInt16LE(FTN_PACKET_HEADER_TYPE, 18); buffer.writeUInt16LE(-1 === packetHeader.origNet ? 0xffff : packetHeader.origNet, 20); buffer.writeUInt16LE(packetHeader.destNet, 22); buffer.writeUInt8(packetHeader.prodCodeLo, 24); buffer.writeUInt8(packetHeader.prodRevHi, 25); - + const pass = ftn.stringToNullPaddedBuffer(packetHeader.password, 8); pass.copy(buffer, 26); - + buffer.writeUInt16LE(packetHeader.origZone, 34); buffer.writeUInt16LE(packetHeader.destZone, 36); buffer.writeUInt16LE(packetHeader.auxNet, 38); @@ -311,7 +311,7 @@ function Packet(options) { buffer.writeUInt16LE(packetHeader.origPoint, 50); buffer.writeUInt16LE(packetHeader.destPoint, 52); buffer.writeUInt32LE(packetHeader.prodData, 54); - + return buffer; }; @@ -321,22 +321,22 @@ function Packet(options) { buffer.writeUInt16LE(packetHeader.origNode, 0); buffer.writeUInt16LE(packetHeader.destNode, 2); buffer.writeUInt16LE(packetHeader.year, 4); - buffer.writeUInt16LE(packetHeader.month, 6); + buffer.writeUInt16LE(packetHeader.month, 6); buffer.writeUInt16LE(packetHeader.day, 8); buffer.writeUInt16LE(packetHeader.hour, 10); buffer.writeUInt16LE(packetHeader.minute, 12); buffer.writeUInt16LE(packetHeader.second, 14); - + buffer.writeUInt16LE(packetHeader.baud, 16); buffer.writeUInt16LE(FTN_PACKET_HEADER_TYPE, 18); buffer.writeUInt16LE(-1 === packetHeader.origNet ? 0xffff : packetHeader.origNet, 20); buffer.writeUInt16LE(packetHeader.destNet, 22); buffer.writeUInt8(packetHeader.prodCodeLo, 24); buffer.writeUInt8(packetHeader.prodRevHi, 25); - + const pass = ftn.stringToNullPaddedBuffer(packetHeader.password, 8); pass.copy(buffer, 26); - + buffer.writeUInt16LE(packetHeader.origZone, 34); buffer.writeUInt16LE(packetHeader.destZone, 36); buffer.writeUInt16LE(packetHeader.auxNet, 38); @@ -376,9 +376,9 @@ function Packet(options) { // likely need to re-decode as the specified encoding // * SAUCE is binary-ish data, so we need to inspect for it before any // decoding occurs - // + // let messageBodyData = { - message : [], + message : [], kludgeLines : {}, // KLUDGE:[value1, value2, ...] map seenBy : [], }; @@ -411,7 +411,7 @@ function Packet(options) { messageBodyData.kludgeLines[key] = value; } } - + let encoding = 'cp437'; async.series( @@ -426,12 +426,12 @@ function Packet(options) { if(!err) { // we read some SAUCE - don't re-process that portion into the body messageBodyBuffer = messageBodyBuffer.slice(0, sauceHeaderPosition) + messageBodyBuffer.slice(sauceHeaderPosition + sauce.SAUCE_SIZE); -// messageBodyBuffer = messageBodyBuffer.slice(0, sauceHeaderPosition); + // messageBodyBuffer = messageBodyBuffer.slice(0, sauceHeaderPosition); messageBodyData.sauce = theSauce; } else { - console.log(err) + Log.warn( { error : err.message }, 'Found what looks like to be a SAUCE record, but failed to read'); } - callback(null); // failure to read SAUCE is OK + return callback(null); // failure to read SAUCE is OK }); } else { callback(null); @@ -482,7 +482,7 @@ function Packet(options) { Log.debug( { encoding : encoding, error : e.toString() }, 'Error decoding. Falling back to ASCII'); decoded = iconv.decode(messageBodyBuffer, 'ascii'); } - + const messageLines = strUtil.splitTextAtTerms(decoded.replace(/\xec/g, '')); let endOfMessage = false; @@ -491,13 +491,13 @@ function Packet(options) { messageBodyData.message.push(''); return; } - + if(line.startsWith('AREA:')) { messageBodyData.area = line.substring(line.indexOf(':') + 1).trim(); } else if(line.startsWith('--- ')) { // Tear Lines are tracked allowing for specialized display/etc. messageBodyData.tearLine = line; - } else if(/^[ ]{1,2}\* Origin\: /.test(line)) { // To spec is " * Origin: ..." + } else if(/^[ ]{1,2}\* Origin: /.test(line)) { // To spec is " * Origin: ..." messageBodyData.originLine = line; endOfMessage = true; // Anything past origin is not part of the message body } else if(line.startsWith('SEEN-BY:')) { @@ -523,7 +523,7 @@ function Packet(options) { } ); }; - + this.parsePacketMessages = function(packetBuffer, iterator, cb) { binary.parse(packetBuffer) .word16lu('messageType') @@ -540,22 +540,22 @@ function Packet(options) { .scan('message', NULL_TERM_BUFFER) .tap(function tapped(msgData) { // no arrow function; want classic this if(!msgData.messageType) { - // end marker -- no more messages + // end marker -- no more messages return cb(null); } - + if(FTN_PACKET_MESSAGE_TYPE != msgData.messageType) { return cb(new Error('Unsupported message type: ' + msgData.messageType)); } - - const read = + + const read = 14 + // fixed header size msgData.modDateTime.length + 1 + msgData.toUserName.length + 1 + msgData.fromUserName.length + 1 + msgData.subject.length + 1 + msgData.message.length + 1; - + // // Convert null terminated arrays to strings // @@ -575,7 +575,7 @@ function Packet(options) { subject : convMsgData.subject, modTimestamp : ftn.getDateFromFtnDateTime(convMsgData.modDateTime), }); - + msg.meta.FtnProperty = {}; msg.meta.FtnProperty.ftn_orig_node = msgData.ftn_orig_node; msg.meta.FtnProperty.ftn_dest_node = msgData.ftn_dest_node; @@ -587,31 +587,31 @@ function Packet(options) { self.processMessageBody(msgData.message, messageBodyData => { msg.message = messageBodyData.message; msg.meta.FtnKludge = messageBodyData.kludgeLines; - + if(messageBodyData.tearLine) { msg.meta.FtnProperty.ftn_tear_line = messageBodyData.tearLine; - + if(self.options.keepTearAndOrigin) { msg.message += `\r\n${messageBodyData.tearLine}\r\n`; } } - + if(messageBodyData.seenBy.length > 0) { msg.meta.FtnProperty.ftn_seen_by = messageBodyData.seenBy; } - + if(messageBodyData.area) { msg.meta.FtnProperty.ftn_area = messageBodyData.area; } - + if(messageBodyData.originLine) { msg.meta.FtnProperty.ftn_origin = messageBodyData.originLine; - + if(self.options.keepTearAndOrigin) { msg.message += `${messageBodyData.originLine}\r\n`; } } - + // // If we have a UTC offset kludge (e.g. TZUTC) then update // modDateTime with it @@ -619,7 +619,7 @@ function Packet(options) { if(_.isString(msg.meta.FtnKludge.TZUTC) && msg.meta.FtnKludge.TZUTC.length > 0) { msg.modDateTime = msg.modTimestamp.utcOffset(msg.meta.FtnKludge.TZUTC); } - + const nextBuf = packetBuffer.slice(read); if(nextBuf.length > 0) { let next = function(e) { @@ -629,12 +629,12 @@ function Packet(options) { self.parsePacketMessages(nextBuf, iterator, cb); } }; - + iterator('message', msg, next); } else { cb(null); } - }); + }); }); }; @@ -702,7 +702,7 @@ function Packet(options) { // // message: unbound length, NULL term'd - // + // // We need to build in various special lines - kludges, area, // seen-by, etc. // @@ -716,7 +716,7 @@ function Packet(options) { if(message.meta.FtnProperty.ftn_area) { msgBody += `AREA:${message.meta.FtnProperty.ftn_area}\r`; // note: no ^A (0x01) } - + // :TODO: DRY with similar function in this file! Object.keys(message.meta.FtnKludge).forEach(k => { switch(k) { @@ -731,7 +731,7 @@ function Packet(options) { break; default : - msgBody += getAppendMeta(`\x01${k}`, message.meta.FtnKludge[k]); + msgBody += getAppendMeta(`\x01${k}`, message.meta.FtnKludge[k]); break; } }); @@ -780,22 +780,22 @@ function Packet(options) { // msgBody += getAppendMeta('SEEN-BY', message.meta.FtnProperty.ftn_seen_by); // note: no ^A (0x01) msgBody += getAppendMeta('\x01PATH', message.meta.FtnKludge['PATH']); - + let msgBodyEncoded; try { msgBodyEncoded = iconv.encode(msgBody + '\0', options.encoding); } catch(e) { msgBodyEncoded = iconv.encode(msgBody + '\0', 'ascii'); } - + return callback( - null, - Buffer.concat( [ - basicHeader, - toUserNameBuf, - fromUserNameBuf, + null, + Buffer.concat( [ + basicHeader, + toUserNameBuf, + fromUserNameBuf, subjectBuf, - msgBodyEncoded + msgBodyEncoded ]) ); } @@ -808,7 +808,7 @@ function Packet(options) { this.writeMessage = function(message, ws, options) { let basicHeader = new Buffer(34); - + basicHeader.writeUInt16LE(FTN_PACKET_MESSAGE_TYPE, 0); basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_orig_node, 2); basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_dest_node, 4); @@ -827,7 +827,7 @@ function Packet(options) { let encBuf = iconv.encode(message.toUserName + '\0', 'CP437').slice(0, 36); encBuf[encBuf.length - 1] = '\0'; // ensure it's null term'd ws.write(encBuf); - + encBuf = iconv.encode(message.fromUserName + '\0', 'CP437').slice(0, 36); encBuf[encBuf.length - 1] = '\0'; // ensure it's null term'd ws.write(encBuf); @@ -839,7 +839,7 @@ function Packet(options) { // // message: unbound length, NULL term'd - // + // // We need to build in various special lines - kludges, area, // seen-by, etc. // @@ -866,7 +866,7 @@ function Packet(options) { if(message.meta.FtnProperty.ftn_area) { msgBody += `AREA:${message.meta.FtnProperty.ftn_area}\r`; // note: no ^A (0x01) } - + Object.keys(message.meta.FtnKludge).forEach(k => { switch(k) { case 'PATH' : break; // skip & save for last @@ -889,8 +889,8 @@ function Packet(options) { if(message.meta.FtnProperty.ftn_tear_line) { msgBody += `${message.meta.FtnProperty.ftn_tear_line}\r`; } - - // + + // // Origin line should be near the bottom of a message // if(message.meta.FtnProperty.ftn_origin) { @@ -918,11 +918,11 @@ function Packet(options) { if(err) { return callback(err); } - + let next = function(e) { callback(e); }; - + iterator('header', header, next); }); }, @@ -934,7 +934,7 @@ function Packet(options) { } ], cb // complete - ); + ); }; } @@ -954,7 +954,7 @@ Packet.Attribute = { InTransit : 0x0020, Orphan : 0x0040, KillSent : 0x0080, - Local : 0x0100, // Message is from *this* system + Local : 0x0100, // Message is from *this* system Hold : 0x0200, Reserved0 : 0x0400, FileRequest : 0x0800, @@ -998,7 +998,7 @@ Packet.prototype.writeHeader = function(ws, packetHeader) { Packet.prototype.writeMessageEntry = function(ws, msgEntry) { ws.write(msgEntry); - return msgEntry.length; + return msgEntry.length; }; Packet.prototype.writeTerminator = function(ws) { @@ -1014,11 +1014,11 @@ Packet.prototype.writeStream = function(ws, messages, options) { if(!_.isBoolean(options.terminatePacket)) { options.terminatePacket = true; } - + if(_.isObject(options.packetHeader)) { this.writePacketHeader(options.packetHeader, ws); } - + options.encoding = options.encoding || 'utf8'; messages.forEach(msg => { @@ -1034,12 +1034,12 @@ Packet.prototype.write = function(path, packetHeader, messages, options) { if(!_.isArray(messages)) { messages = [ messages ]; } - + options = options || { encoding : 'utf8' }; // utf-8 = 'CHRS UTF-8 4' this.writeStream( fs.createWriteStream(path), // :TODO: specify mode/etc. messages, - { packetHeader : packetHeader, terminatePacket : true } - ); + Object.assign( { packetHeader : packetHeader, terminatePacket : true }, options) + ); }; diff --git a/core/ftn_util.js b/core/ftn_util.js index 39093fab..03040484 100644 --- a/core/ftn_util.js +++ b/core/ftn_util.js @@ -45,7 +45,7 @@ exports.getQuotePrefix = getQuotePrefix; // See list here: https://github.com/Mithgol/node-fidonet-jam -function stringToNullPaddedBuffer(s, bufLen) { +function stringToNullPaddedBuffer(s, bufLen) { let buffer = new Buffer(bufLen).fill(0x00); let enc = iconv.encode(s, 'CP437').slice(0, bufLen); for(let i = 0; i < enc.length; ++i) { @@ -56,7 +56,7 @@ function stringToNullPaddedBuffer(s, bufLen) { // // Convert a FTN style DateTime string to a Date object -// +// // :TODO: Name the next couple methods better - for FTN *packets* function getDateFromFtnDateTime(dateTime) { // @@ -103,7 +103,7 @@ function getMessageSerialNumber(messageId) { // // Return a FTS-0009.001 compliant MSGID value given a message // See http://ftsc.org/docs/fts-0009.001 -// +// // "A MSGID line consists of the string "^AMSGID:" (where ^A is a // control-A (hex 01) and the double-quotes are not part of the // string), followed by a space, the address of the originating @@ -113,9 +113,9 @@ function getMessageSerialNumber(messageId) { // ^AMSGID: origaddr serialno // // The originating address should be specified in a form that -// constitutes a valid return address for the originating network. +// constitutes a valid return address for the originating network. // If the originating address is enclosed in double-quotes, the -// entire string between the beginning and ending double-quotes is +// entire string between the beginning and ending double-quotes is // considered to be the orginating address. A double-quote character // within a quoted address is represented by by two consecutive // double-quote characters. The serial number may be any eight @@ -123,13 +123,13 @@ function getMessageSerialNumber(messageId) { // messages from a given system may have the same serial number // within a three years. The manner in which this serial number is // generated is left to the implementor." -// +// // // Examples & Implementations // // Synchronet: .@ // 2606.agora-agn_tst@46:1/142 19609217 -// +// // Mystic: // 46:3/102 46686263 // @@ -145,10 +145,10 @@ function getMessageSerialNumber(messageId) { // function getMessageIdentifier(message, address, isNetMail = false) { const addrStr = new Address(address).toString('5D'); - return isNetMail ? + return isNetMail ? `${addrStr} ${getMessageSerialNumber(message.messageId)}` : `${message.messageId}.${message.areaTag.toLowerCase()}@${addrStr} ${getMessageSerialNumber(message.messageId)}` - ; + ; } // @@ -166,7 +166,7 @@ function getProductIdentifier() { } // -// Return a FRL-1004 style time zone offset for a +// Return a FRL-1004 style time zone offset for a // 'TZUTC' kludge line // // http://ftsc.org/docs/frl-1004.002 @@ -178,10 +178,10 @@ function getUTCTimeZoneOffset() { // // Get a FSC-0032 style quote prefix // http://ftsc.org/docs/fsc-0032.001 -// +// function getQuotePrefix(name) { let initials; - + const parts = name.split(' '); if(parts.length > 1) { // First & Last initials - (Bryan Ashby -> BA) @@ -199,7 +199,7 @@ function getQuotePrefix(name) { // http://ftsc.org/docs/fts-0004.001 // function getOrigin(address) { - const origin = _.has(Config, 'messageNetworks.originLine') ? + const origin = _.has(Config, 'messageNetworks.originLine') ? Config.messageNetworks.originLine : Config.general.boardName; @@ -220,16 +220,12 @@ function getVia(address) { /* FRL-1005.001 states teh following format: - ^AVia: @YYYYMMDD.HHMMSS[.Precise][.Time Zone] + ^AVia: @YYYYMMDD.HHMMSS[.Precise][.Time Zone] [Serial Number] */ const addrStr = new Address(address).toString('5D'); const dateTime = moment().utc().format('YYYYMMDD.HHmmSS.SSSS.UTC'); - - const version = packageJson.version - .replace(/\-/g, '.') - .replace(/alpha/,'a') - .replace(/beta/,'b'); + const version = getCleanEnigmaVersion(); return `${addrStr} @${dateTime} ENiGMA1/2 ${version}`; } @@ -272,7 +268,7 @@ function parseAbbreviatedNetNodeList(netNodes) { const re = /([0-9]+)\/([0-9]+)\s?|([0-9]+)\s?/g; let net; let m; - let results = []; + let results = []; while(null !== (m = re.exec(netNodes))) { if(m[1] && m[2]) { net = parseInt(m[1]); @@ -288,7 +284,7 @@ function parseAbbreviatedNetNodeList(netNodes) { // // Return a FTS-0004.001 SEEN-BY entry(s) that include // all pre-existing SEEN-BY entries with the addition -// of |additions|. +// of |additions|. // // See http://ftsc.org/docs/fts-0004.001 // and notes at http://ftsc.org/docs/fsc-0043.002. @@ -324,9 +320,9 @@ function getUpdatedSeenByEntries(existingEntries, additions) { if(!_.isArray(existingEntries)) { existingEntries = [ existingEntries ]; } - + if(!_.isString(additions)) { - additions = parseAbbreviatedNetNodeList(getAbbreviatedNetNodeList(additions)); + additions = parseAbbreviatedNetNodeList(getAbbreviatedNetNodeList(additions)); } additions = additions.sort(Address.getComparator()); @@ -361,13 +357,13 @@ const ENCODING_TO_FTS_5003_001_CHARS = { // level 1 - generally should not be used ascii : [ 'ASCII', 1 ], 'us-ascii' : [ 'ASCII', 1 ], - + // level 2 - 8 bit, ASCII based cp437 : [ 'CP437', 2 ], cp850 : [ 'CP850', 2 ], - + // level 3 - reserved - + // level 4 utf8 : [ 'UTF-8', 4 ], 'utf-8' : [ 'UTF-8', 4 ], @@ -381,7 +377,7 @@ function getCharacterSetIdentifierByEncoding(encodingName) { function getEncodingFromCharacterSetIdentifier(chrs) { const ident = chrs.split(' ')[0].toUpperCase(); - + // :TODO: fill in the rest!!! return { // level 1 @@ -399,7 +395,7 @@ function getEncodingFromCharacterSetIdentifier(chrs) { 'SWISS' : 'iso-646', 'UK' : 'iso-646', 'ISO-10' : 'iso-646-10', - + // level 2 'CP437' : 'cp437', 'CP850' : 'cp850', @@ -414,15 +410,15 @@ function getEncodingFromCharacterSetIdentifier(chrs) { 'LATIN-2' : 'iso-8859-2', 'LATIN-5' : 'iso-8859-9', 'LATIN-9' : 'iso-8859-15', - + // level 4 'UTF-8' : 'utf8', - + // deprecated stuff - 'IBMPC' : 'cp1250', // :TODO: validate + 'IBMPC' : 'cp1250', // :TODO: validate '+7_FIDO' : 'cp866', - '+7' : 'cp866', + '+7' : 'cp866', 'MAC' : 'macroman', // :TODO: validate - + }[ident]; } \ No newline at end of file diff --git a/core/horizontal_menu_view.js b/core/horizontal_menu_view.js index 28f4c29d..81d477ad 100644 --- a/core/horizontal_menu_view.js +++ b/core/horizontal_menu_view.js @@ -63,7 +63,7 @@ function HorizontalMenuView(options) { } var text = strUtil.stylizeString( - item.text, + item.text, this.hasFocus && item.focused ? self.focusTextStyle : self.textStyle); var drawWidth = text.length + self.getSpacer().length * 2; // * 2 = sides @@ -72,7 +72,7 @@ function HorizontalMenuView(options) { ansi.goto(self.position.row, item.col) + (index === self.focusedItemIndex ? self.getFocusSGR() : self.getSGR()) + strUtil.pad(text, drawWidth, self.fillChar, 'center') - ); + ); }; } diff --git a/core/key_entry_view.js b/core/key_entry_view.js index cf1ba008..304f8ef3 100644 --- a/core/key_entry_view.js +++ b/core/key_entry_view.js @@ -44,7 +44,7 @@ module.exports = class KeyEntryView extends View { if(key && 'tab' === key.name && !this.eatTabKey) { return this.emit('action', 'next', key); } - + this.emit('action', 'accept'); // NOTE: we don't call super here. KeyEntryView is a special snowflake. } @@ -69,7 +69,7 @@ module.exports = class KeyEntryView extends View { } break; } - + super.setPropertyValue(propName, propValue); } diff --git a/core/last_callers.js b/core/last_callers.js index 3a889468..1bc1f422 100644 --- a/core/last_callers.js +++ b/core/last_callers.js @@ -20,7 +20,7 @@ const _ = require('lodash'); location affiliation ts - + */ exports.moduleInfo = { @@ -65,7 +65,7 @@ exports.getModule = class LastCallersModule extends MenuModule { function fetchHistory(callback) { callersView = vc.getView(MciCodeIds.CallerList); - // fetch up + // fetch up StatLog.getSystemLogEntries('user_login_history', StatLog.Order.TimestampDesc, 200, (err, lh) => { loginHistory = lh; @@ -82,12 +82,12 @@ exports.getModule = class LastCallersModule extends MenuModule { loginHistory = noOpLoginHistory; } } - + // // Finally, we need to trim up the list to the needed size // loginHistory = loginHistory.slice(0, callersView.dimens.height); - + return callback(err); }); }, @@ -99,10 +99,10 @@ exports.getModule = class LastCallersModule extends MenuModule { const dateTimeFormat = self.menuConfig.config.dateTimeFormat || 'ddd MMM DD'; async.each( - loginHistory, + loginHistory, (item, next) => { item.userId = parseInt(item.log_value); - item.ts = moment(item.timestamp).format(dateTimeFormat); + item.ts = moment(item.timestamp).format(dateTimeFormat); User.getUserName(item.userId, (err, userName) => { if(err) { diff --git a/core/logger.js b/core/logger.js index f90aec41..1f1efde2 100644 --- a/core/logger.js +++ b/core/logger.js @@ -12,7 +12,7 @@ module.exports = class Log { static init() { const Config = require('./config.js').config; const logPath = Config.paths.logs; - + const err = this.checkLogPath(logPath); if(err) { console.error(err.message); // eslint-disable-line no-console @@ -29,9 +29,9 @@ module.exports = class Log { err : bunyan.stdSerializers.err, // handle 'err' fields with stack/etc. }; - // try to remove sensitive info by default, e.g. 'password' fields + // try to remove sensitive info by default, e.g. 'password' fields [ 'formData', 'formValue' ].forEach(keyName => { - serializers[keyName] = (fd) => Log.hideSensitive(fd); + serializers[keyName] = (fd) => Log.hideSensitive(fd); }); this.log = bunyan.createLogger({ @@ -46,7 +46,7 @@ module.exports = class Log { if(!fs.statSync(logPath).isDirectory()) { return new Error(`${logPath} is not a directory`); } - + return null; } catch(e) { if('ENOENT' === e.code) { diff --git a/core/login_server_module.js b/core/login_server_module.js index 212d2e27..72958a0c 100644 --- a/core/login_server_module.js +++ b/core/login_server_module.js @@ -28,7 +28,7 @@ module.exports = class LoginServerModule extends ServerModule { } else { client.user.properties.theme_id = conf.config.preLoginTheme; } - + theme.setClientTheme(client, client.user.properties.theme_id); return cb(null); // note: currently useless to use cb here - but this may change...again... } @@ -37,7 +37,7 @@ module.exports = class LoginServerModule extends ServerModule { // // Start tracking the client. We'll assign it an ID which is // just the index in our connections array. - // + // if(_.isUndefined(client.session)) { client.session = {}; } @@ -68,7 +68,7 @@ module.exports = class LoginServerModule extends ServerModule { client.on('close', err => { const logFunc = err ? logger.log.info : logger.log.debug; logFunc( { clientId : client.session.id }, 'Connection closed'); - + clientConns.removeClient(client); }); @@ -80,7 +80,7 @@ module.exports = class LoginServerModule extends ServerModule { // likely just doesn't exist client.term.write('\nIdle timeout expired. Goodbye!\n'); client.end(); - } + } }); }); } diff --git a/core/mail_packet.js b/core/mail_packet.js index 3fb8b2d2..fbbb3e76 100644 --- a/core/mail_packet.js +++ b/core/mail_packet.js @@ -33,4 +33,4 @@ MailPacket.prototype.write = function(options) { // emits 'packet' event per packet constructed // assert(_.isArray(options.messages)); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/core/mail_util.js b/core/mail_util.js index 654b1617..4e959389 100644 --- a/core/mail_util.js +++ b/core/mail_util.js @@ -6,7 +6,7 @@ const Message = require('./message.js'); exports.getAddressedToInfo = getAddressedToInfo; -const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; +const EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; /* Input Output diff --git a/core/mask_edit_text_view.js b/core/mask_edit_text_view.js index f99774e6..2c0b6021 100644 --- a/core/mask_edit_text_view.js +++ b/core/mask_edit_text_view.js @@ -25,7 +25,7 @@ exports.MaskEditTextView = MaskEditTextView; // :TODO: // * Hint, e.g. YYYY/MM/DD // * Return values with literals in place -// +// function MaskEditTextView(options) { options.acceptsFocus = miscUtil.valueWithDefault(options.acceptsFocus, true); @@ -49,7 +49,7 @@ function MaskEditTextView(options) { this.drawText = function(s) { var textToDraw = strUtil.stylizeString(s, this.hasFocus ? this.focusTextStyle : this.textStyle); - + assert(textToDraw.length <= self.patternArray.length); // draw out the text we have so far @@ -105,7 +105,7 @@ MaskEditTextView.maskPatternCharacterRegEx = { MaskEditTextView.prototype.setText = function(text) { MaskEditTextView.super_.prototype.setText.call(this, text); - + if(this.patternArray) { // :TODO: This is a hack - see TextView ctor note about setText() this.patternArrayPos = this.patternArray.length; } @@ -130,14 +130,14 @@ MaskEditTextView.prototype.onKeyPress = function(ch, key) { this.clientBackspace(); } else { while(this.patternArrayPos > 0) { - if(_.isRegExp(this.patternArray[this.patternArrayPos])) { + if(_.isRegExp(this.patternArray[this.patternArrayPos])) { this.text = this.text.substr(0, this.text.length - 1); this.client.term.write(ansi.goto(this.position.row, this.getEndOfTextColumn() + 1)); this.clientBackspace(); break; } this.patternArrayPos--; - } + } } } @@ -162,7 +162,7 @@ MaskEditTextView.prototype.onKeyPress = function(ch, key) { this.text += ch; this.patternArrayPos++; - while(this.patternArrayPos < this.patternArray.length && + while(this.patternArrayPos < this.patternArray.length && !_.isRegExp(this.patternArray[this.patternArrayPos])) { this.patternArrayPos++; @@ -186,11 +186,11 @@ MaskEditTextView.prototype.setPropertyValue = function(propName, value) { MaskEditTextView.prototype.getData = function() { var rawData = MaskEditTextView.super_.prototype.getData.call(this); - + if(!rawData || 0 === rawData.length) { return rawData; } - + var data = ''; assert(rawData.length <= this.patternArray.length); diff --git a/core/mci_view_factory.js b/core/mci_view_factory.js index c5b95bb3..eb783d41 100644 --- a/core/mci_view_factory.js +++ b/core/mci_view_factory.js @@ -4,13 +4,12 @@ // ENiGMA½ const TextView = require('./text_view.js').TextView; const EditTextView = require('./edit_text_view.js').EditTextView; -const ButtonView = require('./button_view.js').ButtonView; +const ButtonView = require('./button_view.js').ButtonView; const VerticalMenuView = require('./vertical_menu_view.js').VerticalMenuView; -const HorizontalMenuView = require('./horizontal_menu_view.js').HorizontalMenuView; -const SpinnerMenuView = require('./spinner_menu_view.js').SpinnerMenuView; -const ToggleMenuView = require('./toggle_menu_view.js').ToggleMenuView; +const HorizontalMenuView = require('./horizontal_menu_view.js').HorizontalMenuView; +const SpinnerMenuView = require('./spinner_menu_view.js').SpinnerMenuView; +const ToggleMenuView = require('./toggle_menu_view.js').ToggleMenuView; const MaskEditTextView = require('./mask_edit_text_view.js').MaskEditTextView; -//const StatusBarView = require('./status_bar_view.js').StatusBarView; const KeyEntryView = require('./key_entry_view.js'); const MultiLineEditTextView = require('./multi_line_edit_text_view.js').MultiLineEditTextView; const getPredefinedMCIValue = require('./predefined_mci.js').getPredefinedMCIValue; @@ -37,7 +36,7 @@ MCIViewFactory.UserViewCodes = [ 'XY', ]; -MCIViewFactory.prototype.createFromMCI = function(mci, cb) { +MCIViewFactory.prototype.createFromMCI = function(mci) { assert(mci.code); assert(mci.id > 0); assert(mci.position); @@ -78,7 +77,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci, cb) { // switch(mci.code) { // Text Label (Text View) - case 'TL' : + case 'TL' : setOption(0, 'textStyle'); setOption(1, 'justify'); setWidth(2); @@ -105,14 +104,14 @@ MCIViewFactory.prototype.createFromMCI = function(mci, cb) { break; // Multi Line Edit Text - case 'MT' : + case 'MT' : // :TODO: apply params view = new MultiLineEditTextView(options); break; // Pre-defined Label (Text View) // :TODO: Currently no real point of PL -- @method replaces this pretty much... probably remove - case 'PL' : + case 'PL' : if(mci.args.length > 0) { options.text = getPredefinedMCIValue(this.client, mci.args[0]); if(options.text) { @@ -126,7 +125,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci, cb) { break; // Button - case 'BT' : + case 'BT' : if(mci.args.length > 0) { options.dimens = { width : parseInt(mci.args[0], 10) }; } @@ -144,14 +143,14 @@ MCIViewFactory.prototype.createFromMCI = function(mci, cb) { setOption(0, 'itemSpacing'); setOption(1, 'justify'); setOption(2, 'textStyle'); - + setFocusOption(0, 'focusTextStyle'); view = new VerticalMenuView(options); break; // Horizontal Menu - case 'HM' : + case 'HM' : setOption(0, 'itemSpacing'); setOption(1, 'textStyle'); @@ -165,7 +164,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci, cb) { setOption(1, 'justify'); setFocusOption(0, 'focusTextStyle'); - + view = new SpinnerMenuView(options); break; diff --git a/core/menu_module.js b/core/menu_module.js index 884389ca..783cc40b 100644 --- a/core/menu_module.js +++ b/core/menu_module.js @@ -17,17 +17,17 @@ const assert = require('assert'); const _ = require('lodash'); exports.MenuModule = class MenuModule extends PluginModule { - + constructor(options) { - super(options); + super(options); this.menuName = options.menuName; this.menuConfig = options.menuConfig; this.client = options.client; this.menuConfig.options = options.menuConfig.options || {}; - this.menuMethods = {}; // methods called from @method's + this.menuMethods = {}; // methods called from @method's this.menuConfig.config = this.menuConfig.config || {}; - + this.cls = _.isBoolean(this.menuConfig.options.cls) ? this.menuConfig.options.cls : Config.menus.cls; this.viewControllers = {}; @@ -70,7 +70,7 @@ exports.MenuModule = class MenuModule extends PluginModule { } ); }, - function moveToPromptLocation(callback) { + function moveToPromptLocation(callback) { if(self.menuConfig.prompt) { // :TODO: fetch and move cursor to prompt location, if supplied. See notes/etc. on placements } @@ -171,10 +171,10 @@ exports.MenuModule = class MenuModule extends PluginModule { } nextMenu(cb) { - if(!this.haveNext()) { + if(!this.haveNext()) { return this.prevMenu(cb); // no next, go to prev } - + return this.client.menuStack.next(cb); } @@ -210,7 +210,7 @@ exports.MenuModule = class MenuModule extends PluginModule { haveNext() { return (_.isString(this.menuConfig.next) || _.isArray(this.menuConfig.next)); } - + autoNextMenu(cb) { const self = this; @@ -221,8 +221,8 @@ exports.MenuModule = class MenuModule extends PluginModule { return self.prevMenu(cb); } } - - if(_.has(this.menuConfig, 'runtime.autoNext') && true === this.menuConfig.runtime.autoNext) { + + if(_.has(this.menuConfig, 'runtime.autoNext') && true === this.menuConfig.runtime.autoNext) { if(this.hasNextTimeout()) { setTimeout( () => { return gotoNextMenu(); @@ -297,10 +297,10 @@ exports.MenuModule = class MenuModule extends PluginModule { if(options.clearScreen) { this.client.term.rawWrite(ansi.resetScreen()); } - + return theme.displayThemedAsset( - name, - this.client, + name, + this.client, Object.assign( { font : this.menuConfig.config.font }, options ), (err, artData) => { if(cb) { @@ -361,7 +361,7 @@ exports.MenuModule = class MenuModule extends PluginModule { pausePrompt(position, cb) { if(!cb && _.isFunction(position)) { cb = position; - position = null; + position = null; } this.optionalMoveToPosition(position); @@ -390,7 +390,7 @@ exports.MenuModule = class MenuModule extends PluginModule { if(!view) { return; } - + if(appendMultiLine && (view instanceof MultiLineEditTextView)) { view.addText(text); } else { @@ -401,7 +401,7 @@ exports.MenuModule = class MenuModule extends PluginModule { updateCustomViewTextsWithFilter(formName, startId, fmtObj, options) { options = options || {}; - let textView; + let textView; let customMciId = startId; const config = this.menuConfig.config; const endId = options.endId || 99; // we'll fail to get a view before 99 diff --git a/core/menu_stack.js b/core/menu_stack.js index b4bebea6..26e88cc5 100644 --- a/core/menu_stack.js +++ b/core/menu_stack.js @@ -78,19 +78,19 @@ module.exports = class MenuStack { // :TODO: leave() should really take a cb... this.pop().instance.leave(); // leave & remove current - + const previousModuleInfo = this.pop(); // get previous if(previousModuleInfo) { const opts = { - extraArgs : previousModuleInfo.extraArgs, + extraArgs : previousModuleInfo.extraArgs, savedState : previousModuleInfo.savedState, lastMenuResult : menuResult, }; return this.goto(previousModuleInfo.name, opts, cb); } - + return cb(Errors.MenuStack('No previous menu available', 'NOPREV')); } @@ -106,14 +106,14 @@ module.exports = class MenuStack { if(currentModuleInfo && name === currentModuleInfo.name) { if(cb) { - cb(Errors.MenuStack('Already at supplied menu', 'ALREADYTHERE')); + cb(Errors.MenuStack('Already at supplied menu', 'ALREADYTHERE')); } return; } const loadOpts = { name : name, - client : self.client, + client : self.client, }; if(_.isObject(options)) { diff --git a/core/menu_util.js b/core/menu_util.js index d9e5a1a6..a86690e5 100644 --- a/core/menu_util.js +++ b/core/menu_util.js @@ -42,7 +42,7 @@ function getMenuConfig(client, name, cb) { } else { callback(null); } - } + } ], function complete(err) { cb(err, menuConfig); @@ -53,7 +53,7 @@ function getMenuConfig(client, name, cb) { function loadMenu(options, cb) { assert(_.isObject(options)); assert(_.isString(options.name)); - assert(_.isObject(options.client)); + assert(_.isObject(options.client)); async.waterfall( [ @@ -88,7 +88,7 @@ function loadMenu(options, cb) { return callback(err, modData); }); - }, + }, function createModuleInstance(modData, callback) { Log.trace( { moduleName : modData.name, extraArgs : options.extraArgs, config : modData.config, info : modData.mod.modInfo }, @@ -98,11 +98,11 @@ function loadMenu(options, cb) { try { moduleInstance = new modData.mod.getModule({ menuName : options.name, - menuConfig : modData.config, + menuConfig : modData.config, extraArgs : options.extraArgs, client : options.client, lastMenuResult : options.lastMenuResult, - }); + }); } catch(e) { return callback(e); } @@ -143,7 +143,7 @@ function getFormConfigByIDAndMap(menuConfig, formId, mciMap, cb) { Log.trace( { mciKey : mciReqKey }, 'Using exact configuration key match'); cb(null, formForId[mciReqKey]); return; - } + } // // Generic match @@ -184,24 +184,24 @@ function handleAction(client, formData, conf, cb) { switch(actionAsset.type) { case 'method' : - case 'systemMethod' : + case 'systemMethod' : if(_.isString(actionAsset.location)) { return callModuleMenuMethod( - client, - actionAsset, - paths.join(Config.paths.mods, actionAsset.location), - formData, - conf.extraArgs, + client, + actionAsset, + paths.join(Config.paths.mods, actionAsset.location), + formData, + conf.extraArgs, cb); } else if('systemMethod' === actionAsset.type) { // :TODO: Need to pass optional args here -- conf.extraArgs and args between e.g. () // :TODO: Probably better as system_method.js return callModuleMenuMethod( - client, - actionAsset, - paths.join(__dirname, 'system_menu_method.js'), - formData, - conf.extraArgs, + client, + actionAsset, + paths.join(__dirname, 'system_menu_method.js'), + formData, + conf.extraArgs, cb); } else { // local to current module @@ -209,7 +209,7 @@ function handleAction(client, formData, conf, cb) { if(_.isFunction(currentModule.menuMethods[actionAsset.asset])) { return currentModule.menuMethods[actionAsset.asset](formData, conf.extraArgs, cb); } - + const err = new Error('Method does not exist'); client.log.warn( { method : actionAsset.asset }, err.message); return cb(err); @@ -222,14 +222,14 @@ function handleAction(client, formData, conf, cb) { function handleNext(client, nextSpec, conf, cb) { assert(_.isString(nextSpec) || _.isArray(nextSpec)); - + if(_.isArray(nextSpec)) { nextSpec = client.acs.getConditionalValue(nextSpec, 'next'); } - + const nextAsset = asset.getAssetWithShorthand(nextSpec, 'menu'); // :TODO: getAssetWithShorthand() can return undefined - handle it! - + conf = conf || {}; const extraArgs = conf.extraArgs || {}; @@ -252,7 +252,7 @@ function handleNext(client, nextSpec, conf, cb) { const err = new Error('Method does not exist'); client.log.warn( { method : nextAsset.asset }, err.message); - return cb(err); + return cb(err); } case 'menu' : diff --git a/core/menu_view.js b/core/menu_view.js index 41f1302f..5aed54ca 100644 --- a/core/menu_view.js +++ b/core/menu_view.js @@ -16,7 +16,7 @@ exports.MenuView = MenuView; function MenuView(options) { options.acceptsFocus = miscUtil.valueWithDefault(options.acceptsFocus, true); options.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true); - + View.call(this, options); this.disablePipe = options.disablePipe || false; @@ -65,11 +65,11 @@ util.inherits(MenuView, View); MenuView.prototype.setItems = function(items) { const self = this; - if(items) { + if(items) { this.items = []; items.forEach( itemText => { this.items.push( - { + { text : self.disablePipe ? itemText : pipeToAnsi(itemText, self.client) } ); @@ -79,7 +79,7 @@ MenuView.prototype.setItems = function(items) { MenuView.prototype.removeItem = function(index) { this.items.splice(index, 1); - + if(this.focusItems) { this.focusItems.splice(index, 1); } @@ -95,7 +95,7 @@ MenuView.prototype.getCount = function() { return this.items.length; }; -MenuView.prototype.getItems = function() { +MenuView.prototype.getItems = function() { return this.items.map( item => { return item.text; }); @@ -140,7 +140,7 @@ MenuView.prototype.onKeyPress = function(ch, key) { MenuView.prototype.setFocusItems = function(items) { const self = this; - + if(items) { this.focusItems = []; items.forEach( itemText => { @@ -183,7 +183,7 @@ MenuView.prototype.setHotKeys = function(hotKeys) { this.hotKeys[key.toLowerCase()] = hotKeys[key]; } } else { - this.hotKeys = hotKeys; + this.hotKeys = hotKeys; } } }; diff --git a/core/message.js b/core/message.js index 5d3c8db9..7cac5c79 100644 --- a/core/message.js +++ b/core/message.js @@ -9,9 +9,9 @@ const getISOTimestampString = require('./database.js').getISOTimestampString; const Errors = require('./enig_error.js').Errors; const ANSI = require('./ansi_term.js'); -const { +const { isAnsi, isFormattedLine, - splitTextAtTerms, + splitTextAtTerms, renderSubstr } = require('./string_util.js'); @@ -45,7 +45,7 @@ function Message(options) { this.fromUserName = options.fromUserName || ''; this.subject = options.subject || ''; this.message = options.message || ''; - + if(_.isDate(options.modTimestamp) || moment.isMoment(options.modTimestamp)) { this.modTimestamp = moment(options.modTimestamp); } else if(_.isString(options.modTimestamp)) { @@ -115,7 +115,7 @@ Message.StateFlags0 = { Exported : 0x00000002, // exported to foreign system }; -Message.FtnPropertyNames = { +Message.FtnPropertyNames = { FtnOrigNode : 'ftn_orig_node', FtnDestNode : 'ftn_dest_node', FtnOrigNetwork : 'ftn_orig_network', @@ -166,12 +166,12 @@ Message.createMessageUUID = function(areaTag, modTimestamp, subject, body) { if(!moment.isMoment(modTimestamp)) { modTimestamp = moment(modTimestamp); } - + areaTag = iconvEncode(areaTag.toUpperCase(), 'CP437'); modTimestamp = iconvEncode(modTimestamp.format('DD MMM YY HH:mm:ss'), 'CP437'); subject = iconvEncode(subject.toUpperCase().trim(), 'CP437'); body = iconvEncode(body.replace(/\r\n|[\n\v\f\r\x85\u2028\u2029]/g, '').trim(), 'CP437'); - + return uuidParse.unparse(createNamedUUID(ENIGMA_MESSAGE_UUID_NAMESPACE, Buffer.concat( [ areaTag, modTimestamp, subject, body ] ))); }; @@ -180,8 +180,8 @@ Message.getMessageIdByUuid = function(uuid, cb) { `SELECT message_id FROM message WHERE message_uuid = ? - LIMIT 1;`, - [ uuid ], + LIMIT 1;`, + [ uuid ], (err, row) => { if(err) { cb(err); @@ -210,30 +210,30 @@ Message.getMessageIdsByMetaValue = function(category, name, value, cb) { }; Message.getMetaValuesByMessageId = function(messageId, category, name, cb) { - const sql = + const sql = `SELECT meta_value FROM message_meta WHERE message_id = ? AND meta_category = ? AND meta_name = ?;`; - + msgDb.all(sql, [ messageId, category, name ], (err, rows) => { if(err) { return cb(err); } - + if(0 === rows.length) { return cb(new Error('No value for category/name')); } - + // single values are returned without an array if(1 === rows.length) { return cb(null, rows[0].meta_value); } - + cb(null, rows.map(r => r.meta_value)); // map to array of values only }); }; -Message.getMetaValuesByMessageUuid = function(uuid, category, name, cb) { +Message.getMetaValuesByMessageUuid = function(uuid, category, name, cb) { async.waterfall( [ function getMessageId(callback) { @@ -256,22 +256,22 @@ Message.getMetaValuesByMessageUuid = function(uuid, category, name, cb) { Message.prototype.loadMeta = function(cb) { /* Example of loaded this.meta: - + meta: { System: { - local_to_user_id: 1234, + local_to_user_id: 1234, }, FtnProperty: { ftn_seen_by: [ "1/102 103", "2/42 52 65" ] } - } - */ - - const sql = + } + */ + + const sql = `SELECT meta_category, meta_name, meta_value FROM message_meta WHERE message_id = ?;`; - + let self = this; msgDb.each(sql, [ this.messageId ], (err, row) => { if(!(row.meta_category in self.meta)) { @@ -279,12 +279,12 @@ Message.prototype.loadMeta = function(cb) { self.meta[row.meta_category][row.meta_name] = row.meta_value; } else { if(!(row.meta_name in self.meta[row.meta_category])) { - self.meta[row.meta_category][row.meta_name] = row.meta_value; + self.meta[row.meta_category][row.meta_name] = row.meta_value; } else { if(_.isString(self.meta[row.meta_category][row.meta_name])) { - self.meta[row.meta_category][row.meta_name] = [ self.meta[row.meta_category][row.meta_name] ]; + self.meta[row.meta_category][row.meta_name] = [ self.meta[row.meta_category][row.meta_name] ]; } - + self.meta[row.meta_category][row.meta_name].push(row.meta_value); } } @@ -315,7 +315,7 @@ Message.prototype.load = function(options, cb) { if(!msgRow) { return callback(new Error('Message (no longer) available')); } - + self.messageId = msgRow.message_id; self.areaTag = msgRow.area_tag; self.messageUuid = msgRow.message_uuid; @@ -356,13 +356,13 @@ Message.prototype.persistMetaValue = function(category, name, value, transOrDb, const metaStmt = transOrDb.prepare( `INSERT INTO message_meta (message_id, meta_category, meta_name, meta_value) VALUES (?, ?, ?, ?);`); - + if(!_.isArray(value)) { value = [ value ]; } - + let self = this; - + async.each(value, (v, next) => { metaStmt.run(self.messageId, category, name, v, err => { next(err); @@ -379,7 +379,7 @@ Message.prototype.persist = function(cb) { } const self = this; - + async.waterfall( [ function beginTransaction(callback) { @@ -398,7 +398,7 @@ Message.prototype.persist = function(cb) { trans.run( `INSERT INTO message (area_tag, message_uuid, reply_to_message_id, to_user_name, from_user_name, subject, message, modified_timestamp) - VALUES (?, ?, ?, ?, ?, ?, ?, ?);`, + VALUES (?, ?, ?, ?, ?, ?, ?, ?);`, [ self.areaTag, self.uuid, self.replyToMsgId, self.toUserName, self.fromUserName, self.subject, self.message, getISOTimestampString(msgTimestamp) ], function inserted(err) { // use non-arrow function for 'this' scope if(!err) { @@ -415,15 +415,15 @@ Message.prototype.persist = function(cb) { } /* Example of self.meta: - + meta: { System: { - local_to_user_id: 1234, + local_to_user_id: 1234, }, FtnProperty: { ftn_seen_by: [ "1/102 103", "2/42 52 65" ] } - } + } */ async.each(Object.keys(self.meta), (category, nextCat) => { async.each(Object.keys(self.meta[category]), (name, nextName) => { @@ -433,10 +433,10 @@ Message.prototype.persist = function(cb) { }, err => { nextCat(err); }); - + }, err => { callback(err, trans); - }); + }); }, function storeHashTags(trans, callback) { // :TODO: hash tag support @@ -470,21 +470,21 @@ Message.prototype.getQuoteLines = function(options, cb) { if(!options.termWidth || !options.termHeight || !options.cols) { return cb(Errors.MissingParam()); } - + options.startCol = options.startCol || 1; options.includePrefix = _.get(options, 'includePrefix', true); options.ansiResetSgr = options.ansiResetSgr || ANSI.getSGRFromGraphicRendition( { fg : 39, bg : 49 }, true); options.ansiFocusPrefixSgr = options.ansiFocusPrefixSgr || ANSI.getSGRFromGraphicRendition( { intensity : 'bold', fg : 39, bg : 49 } ); options.isAnsi = options.isAnsi || isAnsi(this.message); // :TODO: If this.isAnsi, use that setting - + /* Some long text that needs to be wrapped and quoted should look right after - doing so, don't ya think? yeah I think so + doing so, don't ya think? yeah I think so - Nu> Some long text that needs to be wrapped and quoted should look right + Nu> Some long text that needs to be wrapped and quoted should look right Nu> after doing so, don't ya think? yeah I think so - Ot> Nu> Some long text that needs to be wrapped and quoted should look + Ot> Nu> Some long text that needs to be wrapped and quoted should look Ot> Nu> right after doing so, don't ya think? yeah I think so */ @@ -498,7 +498,7 @@ Message.prototype.getQuoteLines = function(options, cb) { tabHandling : 'expand', tabWidth : 4, }; - + return wordWrapText(text, wrapOpts).wrapped.map( (w, i) => { return i === 0 ? `${quotePrefix}${w}` : `${quotePrefix}${extraPrefix}${w}`; }); @@ -527,44 +527,44 @@ Message.prototype.getQuoteLines = function(options, cb) { cols : options.cols, rows : 'auto', startCol : options.startCol, - forceLineTerm : true, + forceLineTerm : true, }, (err, prepped) => { prepped = prepped || this.message; - + let lastSgr = ''; const split = splitTextAtTerms(prepped); - + const quoteLines = []; const focusQuoteLines = []; // // Do not include quote prefixes (e.g. XX> ) on ANSI replies (and therefor quote builder) - // as while this works in ENiGMA, other boards such as Mystic, WWIV, etc. will try to + // as while this works in ENiGMA, other boards such as Mystic, WWIV, etc. will try to // strip colors, colorize the lines, etc. If we exclude the prefixes, this seems to do // the trick and allow them to leave them alone! // split.forEach(l => { quoteLines.push(`${lastSgr}${l}`); - + focusQuoteLines.push(`${options.ansiFocusPrefixSgr}>${lastSgr}${renderSubstr(l, 1, l.length - 1)}`); - lastSgr = (l.match(/(?:\x1b\x5b)[\?=;0-9]*m(?!.*(?:\x1b\x5b)[\?=;0-9]*m)/) || [])[0] || ''; // eslint-disable-line no-control-regex + lastSgr = (l.match(/(?:\x1b\x5b)[?=;0-9]*m(?!.*(?:\x1b\x5b)[?=;0-9]*m)/) || [])[0] || ''; // eslint-disable-line no-control-regex }); quoteLines[quoteLines.length - 1] += options.ansiResetSgr; - + return cb(null, quoteLines, focusQuoteLines, true); } ); } else { - const QUOTE_RE = /^ ((?:[A-Za-z0-9]{2}\> )+(?:[A-Za-z0-9]{2}\>)*) */; + const QUOTE_RE = /^ ((?:[A-Za-z0-9]{2}> )+(?:[A-Za-z0-9]{2}>)*) */; const quoted = []; const input = _.trimEnd(this.message).replace(/\b/g, ''); - + // find *last* tearline let tearLinePos = this.getTearLinePosition(input); tearLinePos = -1 === tearLinePos ? input.length : tearLinePos; // we just want the index or the entire string - + input.slice(0, tearLinePos).split(/\r\n\r\n|\n\n/).forEach(paragraph => { // // For each paragraph, a state machine: @@ -612,7 +612,7 @@ Message.prototype.getQuoteLines = function(options, cb) { buf += ` ${line}`; } break; - + case 'quote_line' : if(quoteMatch) { const rem = line.slice(quoteMatch[0].length); @@ -628,7 +628,7 @@ Message.prototype.getQuoteLines = function(options, cb) { state = 'line'; } break; - + default : if(isFormattedLine(line)) { quoted.push(getFormattedLine(line)); @@ -637,12 +637,12 @@ Message.prototype.getQuoteLines = function(options, cb) { buf = 'line' === state ? line : line.replace(/\s/, ''); // trim *first* leading space, if any } break; - } + } }); - + quoted.push(...getWrapped(buf, quoteMatch ? quoteMatch[1] : null)); }); - + input.slice(tearLinePos).split(/\r?\n/).forEach(l => { quoted.push(...getWrapped(l)); }); diff --git a/core/message_area.js b/core/message_area.js index 53dd3086..3c42e23f 100644 --- a/core/message_area.js +++ b/core/message_area.js @@ -40,9 +40,9 @@ function getAvailableMessageConferences(client, options) { options = options || { includeSystemInternal : false }; assert(client || true === options.noClient); - - // perform ACS check per conf & omit system_internal if desired - return _.omitBy(Config.messageConferences, (conf, confTag) => { + + // perform ACS check per conf & omit system_internal if desired + return _.omitBy(Config.messageConferences, (conf, confTag) => { if(!options.includeSystemInternal && 'system_internal' === confTag) { return true; } @@ -60,15 +60,15 @@ function getSortedAvailMessageConferences(client, options) { }); sortAreasOrConfs(confs, 'conf'); - + return confs; } // Return an *object* of available areas within |confTag| function getAvailableMessageAreasByConfTag(confTag, options) { options = options || {}; - - // :TODO: confTag === "" then find default + + // :TODO: confTag === "" then find default if(_.has(Config.messageConferences, [ confTag, 'areas' ])) { const areas = Config.messageConferences[confTag].areas; @@ -92,9 +92,9 @@ function getSortedAvailMessageAreasByConfTag(confTag, options) { area : v, }; }); - + sortAreasOrConfs(areas, 'area'); - + return areas; } @@ -103,7 +103,7 @@ function getDefaultMessageConferenceTag(client, disableAcsCheck) { // Find the first conference marked 'default'. If found, // inspect |client| against *read* ACS using defaults if not // specified. - // + // // If the above fails, just go down the list until we get one // that passes. // @@ -116,14 +116,14 @@ function getDefaultMessageConferenceTag(client, disableAcsCheck) { const conf = Config.messageConferences[defaultConf]; if(true === disableAcsCheck || client.acs.hasMessageConfRead(conf)) { return defaultConf; - } + } } // just use anything we can defaultConf = _.findKey(Config.messageConferences, (conf, confTag) => { return 'system_internal' !== confTag && (true === disableAcsCheck || client.acs.hasMessageConfRead(conf)); }); - + return defaultConf; } @@ -138,19 +138,19 @@ function getDefaultMessageAreaTagByConfTag(client, confTag, disableAcsCheck) { confTag = confTag || getDefaultMessageConferenceTag(client); if(confTag && _.has(Config.messageConferences, [ confTag, 'areas' ])) { - const areaPool = Config.messageConferences[confTag].areas; + const areaPool = Config.messageConferences[confTag].areas; let defaultArea = _.findKey(areaPool, o => o.default); if(defaultArea) { const area = areaPool[defaultArea]; if(true === disableAcsCheck || client.acs.hasMessageAreaRead(area)) { return defaultArea; - } + } } - + defaultArea = _.findKey(areaPool, (area) => { - return (true === disableAcsCheck || client.acs.hasMessageAreaRead(area)); + return (true === disableAcsCheck || client.acs.hasMessageAreaRead(area)); }); - + return defaultArea; } } @@ -159,18 +159,6 @@ function getMessageConferenceByTag(confTag) { return Config.messageConferences[confTag]; } -function getMessageConfByAreaTag(areaTag) { - const confs = Config.messageConferences; - let conf; - _.forEach(confs, (v) => { - if(_.has(v, [ 'areas', areaTag ])) { - conf = v; - return false; // stop iteration - } - }); - return conf; -} - function getMessageConfTagByAreaTag(areaTag) { const confs = Config.messageConferences; return Object.keys(confs).find( (confTag) => { @@ -194,9 +182,9 @@ function getMessageAreaByTag(areaTag, optionalConfTag) { if(_.has(v, [ 'areas', areaTag ])) { area = v.areas[areaTag]; return false; // stop iteration - } + } }); - + return area; } } @@ -206,7 +194,7 @@ function changeMessageConference(client, confTag, cb) { [ function getConf(callback) { const conf = getMessageConferenceByTag(confTag); - + if(conf) { callback(null, conf); } else { @@ -216,7 +204,7 @@ function changeMessageConference(client, confTag, cb) { function getDefaultAreaInConf(conf, callback) { const areaTag = getDefaultMessageAreaTagByConfTag(client, confTag); const area = getMessageAreaByTag(areaTag, confTag); - + if(area) { callback(null, conf, { areaTag : areaTag, area : area } ); } else { @@ -229,7 +217,7 @@ function changeMessageConference(client, confTag, cb) { } else { return callback(null, conf, areaInfo); } - }, + }, function changeConferenceAndArea(conf, areaInfo, callback) { const newProps = { message_conf_tag : confTag, @@ -258,12 +246,12 @@ function changeMessageAreaWithOptions(client, areaTag, options, cb) { [ function getArea(callback) { const area = getMessageAreaByTag(areaTag); - return callback(area ? null : new Error('Invalid message areaTag'), area); + return callback(area ? null : new Error('Invalid message areaTag'), area); }, function validateAccess(area, callback) { - // - // Need at least *read* to access the area - // + // + // Need at least *read* to access the area + // if(!client.acs.hasMessageAreaRead(area)) { return callback(new Error('Access denied to message area')); } else { @@ -294,7 +282,7 @@ function changeMessageAreaWithOptions(client, areaTag, options, cb) { } // -// Temporairly -- e.g. non-persisted -- change to an area and it's +// Temporairly -- e.g. non-persisted -- change to an area and it's // associated underlying conference. ACS is checked for both. // // This is useful for example when doing a new scan @@ -312,7 +300,7 @@ function tempChangeMessageConfAndArea(client, areaTag) { if(!client.acs.hasMessageConfRead(conf) || !client.acs.hasMessageAreaRead(area)) { return false; } - + client.user.properties.message_conf_tag = confTag; client.user.properties.message_area_tag = areaTag; @@ -324,7 +312,7 @@ function changeMessageArea(client, areaTag, cb) { } function getMessageFromRow(row) { - return { + return { messageId : row.message_id, messageUuid : row.message_uuid, replyToMsgId : row.reply_to_message_id, @@ -346,8 +334,8 @@ function getNewMessageDataInAreaForUserSql(userId, areaTag, lastMessageId, what) // // * Only messages > |lastMessageId| should be returned/counted // - const selectWhat = ('count' === what) ? - 'COUNT() AS count' : + const selectWhat = ('count' === what) ? + 'COUNT() AS count' : 'message_id, message_uuid, reply_to_message_id, to_user_name, from_user_name, subject, modified_timestamp, view_count'; let sql = @@ -386,7 +374,7 @@ function getNewMessageCountInAreaForUser(userId, areaTag, cb) { msgDb.get(sql, (err, row) => { return callback(err, row ? row.count : 0); }); - } + } ], cb ); @@ -421,7 +409,7 @@ function getNewMessagesInAreaForUser(userId, areaTag, cb) { function complete(err) { cb(err, msgList); } - ); + ); } function getMessageListForArea(options, areaTag, cb) { @@ -435,7 +423,7 @@ function getMessageListForArea(options, areaTag, cb) { /* [ - { + { messageId, messageUuid, replyToId, toUserName, fromUserName, subject, modTimestamp, status(new|old), viewCount @@ -448,13 +436,13 @@ function getMessageListForArea(options, areaTag, cb) { async.series( [ function fetchMessages(callback) { - let sql = + let sql = `SELECT message_id, message_uuid, reply_to_message_id, to_user_name, from_user_name, subject, modified_timestamp, view_count FROM message WHERE area_tag = ?`; if(Message.isPrivateAreaTag(areaTag)) { - sql += + sql += ` AND message_id IN ( SELECT message_id FROM message_meta @@ -462,7 +450,7 @@ function getMessageListForArea(options, areaTag, cb) { )`; } - sql += ' ORDER BY message_id;'; + sql += ' ORDER BY message_id;'; msgDb.each( sql, @@ -551,12 +539,12 @@ function updateMessageAreaLastReadId(userId, areaTag, messageId, allowOlder, cb) ], function complete(err, didUpdate) { if(err) { - Log.debug( - { error : err.toString(), userId : userId, areaTag : areaTag, messageId : messageId }, + Log.debug( + { error : err.toString(), userId : userId, areaTag : areaTag, messageId : messageId }, 'Failed updating area last read ID'); } else { if(true === didUpdate) { - Log.trace( + Log.trace( { userId : userId, areaTag : areaTag, messageId : messageId }, 'Area last read ID updated'); } @@ -574,7 +562,7 @@ function persistMessage(message, cb) { }, function recordToMessageNetworks(callback) { return msgNetRecord(message, callback); - } + } ], cb ); @@ -582,7 +570,7 @@ function persistMessage(message, cb) { // method exposed for event scheduler function trimMessageAreasScheduledEvent(args, cb) { - + function trimMessageAreaByMaxMessages(areaInfo, cb) { if(0 === areaInfo.maxMessages) { return cb(null); @@ -605,7 +593,7 @@ function trimMessageAreasScheduledEvent(args, cb) { Log.debug( { areaInfo : areaInfo, type : 'maxMessages', count : this.changes }, 'Area trimmed successfully'); } return cb(err); - } + } ); } @@ -690,7 +678,7 @@ function trimMessageAreasScheduledEvent(args, cb) { trimMessageAreaByMaxAgeDays(areaInfo, err => { return next(err); - }); + }); }); }, callback diff --git a/core/mime_util.js b/core/mime_util.js index 1e2bd32c..a110572c 100644 --- a/core/mime_util.js +++ b/core/mime_util.js @@ -36,6 +36,6 @@ function resolveMimeType(query) { if(mimeTypes.extensions[query]) { return query; // alreaed a mime-type } - + return mimeTypes.lookup(query) || undefined; // lookup() returns false; we want undefined } \ No newline at end of file diff --git a/core/misc_util.js b/core/misc_util.js index afe33dee..70bbb5e2 100644 --- a/core/misc_util.js +++ b/core/misc_util.js @@ -36,10 +36,10 @@ function resolvePath(path) { function getCleanEnigmaVersion() { return packageJson.version - .replace(/\-/g, '.') + .replace(/-/g, '.') .replace(/alpha/,'a') .replace(/beta/,'b') - ; + ; } // See also ftn_util.js getTearLine() & getProductIdentifier() diff --git a/core/mod_mixins.js b/core/mod_mixins.js index 291e0cc9..48546825 100644 --- a/core/mod_mixins.js +++ b/core/mod_mixins.js @@ -5,7 +5,7 @@ const messageArea = require('../core/message_area.js'); exports.MessageAreaConfTempSwitcher = Sup => class extends Sup { - + tempMessageConfAndAreaSwitch(messageAreaTag) { messageAreaTag = messageAreaTag || this.messageAreaTag; if(!messageAreaTag) { @@ -14,7 +14,7 @@ exports.MessageAreaConfTempSwitcher = Sup => class extends Sup { this.prevMessageConfAndArea = { confTag : this.client.user.properties.message_conf_tag, - areaTag : this.client.user.properties.message_area_tag, + areaTag : this.client.user.properties.message_area_tag, }; if(!messageArea.tempChangeMessageConfAndArea(this.client, this.messageAreaTag)) { @@ -25,7 +25,7 @@ exports.MessageAreaConfTempSwitcher = Sup => class extends Sup { tempMessageConfAndAreaRestore() { if(this.prevMessageConfAndArea) { this.client.user.properties.message_conf_tag = this.prevMessageConfAndArea.confTag; - this.client.user.properties.message_area_tag = this.prevMessageConfAndArea.areaTag; + this.client.user.properties.message_area_tag = this.prevMessageConfAndArea.areaTag; } } }; diff --git a/core/msg_area_list.js b/core/msg_area_list.js index eaedbef8..96b0a51c 100644 --- a/core/msg_area_list.js +++ b/core/msg_area_list.js @@ -36,7 +36,7 @@ exports.moduleInfo = { const MciViewIds = { AreaList : 1, SelAreaInfo1 : 2, - SelAreaInfo2 : 3, + SelAreaInfo2 : 3, }; exports.getModule = class MessageAreaListModule extends MenuModule { @@ -61,7 +61,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule { self.client.term.pipeWrite(`\n|00Cannot change area: ${err.message}\n`); self.prevMenuOnTimeout(1000, cb); - } else { + } else { if(_.isString(area.art)) { const dispOptions = { client : self.client, @@ -72,7 +72,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule { displayThemeArt(dispOptions, () => { // pause by default, unless explicitly told not to - if(_.has(area, 'options.pause') && false === area.options.pause) { + if(_.has(area, 'options.pause') && false === area.options.pause) { return self.prevMenuOnTimeout(1000, cb); } else { self.pausePrompt( () => { @@ -98,9 +98,9 @@ exports.getModule = class MessageAreaListModule extends MenuModule { }, timeout); } - updateGeneralAreaInfoViews(areaIndex) { - // :TODO: these concepts have been replaced with the {someKey} style formatting - update me! - /* experimental: not yet avail + // :TODO: these concepts have been replaced with the {someKey} style formatting - update me! + /* + updateGeneralAreaInfoViews(areaIndex) { const areaInfo = self.messageAreas[areaIndex]; [ MciViewIds.SelAreaInfo1, MciViewIds.SelAreaInfo2 ].forEach(mciId => { @@ -109,8 +109,8 @@ exports.getModule = class MessageAreaListModule extends MenuModule { v.setFormatObject(areaInfo.area); } }); - */ } + */ mciReady(mciData, cb) { super.mciReady(mciData, err => { @@ -137,7 +137,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule { function populateAreaListView(callback) { const listFormat = self.menuConfig.config.listFormat || '{index} ) - {name}'; const focusListFormat = self.menuConfig.config.focusListFormat || listFormat; - + const areaListView = vc.getView(MciViewIds.AreaList); let i = 1; areaListView.setItems(_.map(self.messageAreas, v => { @@ -145,7 +145,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule { index : i++, areaTag : v.area.areaTag, name : v.area.name, - desc : v.area.desc, + desc : v.area.desc, }); })); @@ -155,7 +155,7 @@ exports.getModule = class MessageAreaListModule extends MenuModule { index : i++, areaTag : v.area.areaTag, name : v.area.name, - desc : v.area.desc, + desc : v.area.desc, }); })); diff --git a/core/msg_area_post_fse.js b/core/msg_area_post_fse.js index c13f39a6..3ffef698 100644 --- a/core/msg_area_post_fse.js +++ b/core/msg_area_post_fse.js @@ -48,9 +48,9 @@ exports.getModule = class AreaPostFSEModule extends FullScreenEditorModule { self.client.log.info( { to : msg.toUserName, subject : msg.subject, uuid : msg.uuid }, 'Message persisted' - ); + ); } - + return self.nextMenu(cb); } ); diff --git a/core/msg_area_view_fse.js b/core/msg_area_view_fse.js index 02915f79..0f25c63f 100644 --- a/core/msg_area_view_fse.js +++ b/core/msg_area_view_fse.js @@ -69,7 +69,7 @@ exports.getModule = class AreaViewFSEModule extends FullScreenEditorModule { case 'down arrow' : bodyView.scrollDocumentUp(); break; case 'up arrow' : bodyView.scrollDocumentDown(); break; case 'page up' : bodyView.keyPressPageUp(); break; - case 'page down' : bodyView.keyPressPageDown(); break; + case 'page down' : bodyView.keyPressPageDown(); break; } // :TODO: need to stop down/page down if doing so would push the last @@ -83,13 +83,13 @@ exports.getModule = class AreaViewFSEModule extends FullScreenEditorModule { const modOpts = { extraArgs : { messageAreaTag : self.messageAreaTag, - replyToMessage : self.message, - } + replyToMessage : self.message, + } }; return self.gotoMenu(extraArgs.menu, modOpts, cb); } - + self.client.log(extraArgs, 'Missing extraArgs.menu'); return cb(null); } diff --git a/core/msg_conf_list.js b/core/msg_conf_list.js index 6f42cf36..43e57820 100644 --- a/core/msg_conf_list.js +++ b/core/msg_conf_list.js @@ -21,10 +21,10 @@ exports.moduleInfo = { const MciViewIds = { ConfList : 1, - + // :TODO: // # areas in conf .... see Obv/2, iNiQ, ... - // + // }; exports.getModule = class MessageConfListModule extends MenuModule { @@ -33,16 +33,16 @@ exports.getModule = class MessageConfListModule extends MenuModule { this.messageConfs = messageArea.getSortedAvailMessageConferences(this.client); const self = this; - + this.menuMethods = { changeConference : function(formData, extraArgs, cb) { if(1 === formData.submitId) { let conf = self.messageConfs[formData.value.conf]; const confTag = conf.confTag; - conf = conf.conf; // what we want is embedded + conf = conf.conf; // what we want is embedded messageArea.changeMessageConference(self.client, confTag, err => { - if(err) { + if(err) { self.client.term.pipeWrite(`\n|00Cannot change conference: ${err.message}\n`); setTimeout( () => { @@ -59,7 +59,7 @@ exports.getModule = class MessageConfListModule extends MenuModule { displayThemeArt(dispOptions, () => { // pause by default, unless explicitly told not to - if(_.has(conf, 'options.pause') && false === conf.options.pause) { + if(_.has(conf, 'options.pause') && false === conf.options.pause) { return self.prevMenuOnTimeout(1000, cb); } else { self.pausePrompt( () => { @@ -108,7 +108,7 @@ exports.getModule = class MessageConfListModule extends MenuModule { function populateConfListView(callback) { const listFormat = self.menuConfig.config.listFormat || '{index} ) - {name}'; const focusListFormat = self.menuConfig.config.focusListFormat || listFormat; - + const confListView = vc.getView(MciViewIds.ConfList); let i = 1; confListView.setItems(_.map(self.messageConfs, v => { @@ -116,7 +116,7 @@ exports.getModule = class MessageConfListModule extends MenuModule { index : i++, confTag : v.conf.confTag, name : v.conf.name, - desc : v.conf.desc, + desc : v.conf.desc, }); })); @@ -126,7 +126,7 @@ exports.getModule = class MessageConfListModule extends MenuModule { index : i++, confTag : v.conf.confTag, name : v.conf.name, - desc : v.conf.desc, + desc : v.conf.desc, }); })); diff --git a/core/msg_list.js b/core/msg_list.js index e5a69e80..19ef30cd 100644 --- a/core/msg_list.js +++ b/core/msg_list.js @@ -26,7 +26,7 @@ const moment = require('moment'); MCI codes: VM1 : Message list - TL2 : Message info 1: { msgNumSelected, msgNumTotal } + TL2 : Message info 1: { msgNumSelected, msgNumTotal } */ exports.moduleInfo = { @@ -84,9 +84,9 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher( // due to the size of |messageList|. See https://github.com/trentm/node-bunyan/issues/189 // modOpts.extraArgs.toJSON = function() { - const logMsgList = (this.messageList.length <= 4) ? - this.messageList : - this.messageList.slice(0, 2).concat(this.messageList.slice(-2)); + const logMsgList = (this.messageList.length <= 4) ? + this.messageList : + this.messageList.slice(0, 2).concat(this.messageList.slice(-2)); return { messageAreaTag : this.messageAreaTag, @@ -158,14 +158,14 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher( if(_.isArray(self.messageList)) { return callback(0 === self.messageList.length ? new Error('No messages in area') : null); } - + messageArea.getMessageListForArea( { client : self.client }, self.messageAreaTag, function msgs(err, msgList) { if(!msgList || 0 === msgList.length) { return callback(new Error('No messages in area')); } - + self.messageList = msgList; - return callback(err); + return callback(err); }); }, function getLastReadMesageId(callback) { @@ -187,15 +187,15 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher( if(_.isUndefined(self.initialFocusIndex) && listItem.messageId > self.lastReadId) { self.initialFocusIndex = index; - } + } }); return callback(null); }, function populateList(callback) { - const msgListView = vc.getView(MCICodesIDs.MsgList); - const listFormat = self.menuConfig.config.listFormat || '{msgNum} - {subject} - {toUserName}'; + const msgListView = vc.getView(MCICodesIDs.MsgList); + const listFormat = self.menuConfig.config.listFormat || '{msgNum} - {subject} - {toUserName}'; const focusListFormat = self.menuConfig.config.focusListFormat || listFormat; // :TODO: default change color here - const messageInfo1Format = self.menuConfig.config.messageInfo1Format || '{msgNumSelected} / {msgNumTotal}'; + const messageInfo1Format = self.menuConfig.config.messageInfo1Format || '{msgNumSelected} / {msgNumTotal}'; // :TODO: This can take a very long time to load large lists. What we need is to implement the "owner draw" concept in // which items are requested (e.g. their format at least) *as-needed* vs trying to get the format for all of them at once @@ -211,10 +211,10 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher( msgListView.on('index update', idx => { self.setViewText( 'allViews', - MCICodesIDs.MsgInfo1, + MCICodesIDs.MsgInfo1, stringFormat(messageInfo1Format, { msgNumSelected : (idx + 1), msgNumTotal : self.messageList.length } )); }); - + if(self.initialFocusIndex > 0) { // note: causes redraw() msgListView.setFocusItemIndex(self.initialFocusIndex); @@ -228,29 +228,29 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher( const messageInfo1Format = self.menuConfig.config.messageInfo1Format || '{msgNumSelected} / {msgNumTotal}'; self.setViewText( 'allViews', - MCICodesIDs.MsgInfo1, + MCICodesIDs.MsgInfo1, stringFormat(messageInfo1Format, { msgNumSelected : self.initialFocusIndex + 1, msgNumTotal : self.messageList.length } )); return callback(null); }, - ], + ], err => { if(err) { - self.client.log.error( { error : err.message }, 'Error loading message list'); + self.client.log.error( { error : err.message }, 'Error loading message list'); } return cb(err); } ); - }); + }); } getSaveState() { - return { initialFocusIndex : this.initialFocusIndex }; + return { initialFocusIndex : this.initialFocusIndex }; } restoreSavedState(savedState) { if(savedState) { this.initialFocusIndex = savedState.initialFocusIndex; - } + } } getMenuResult() { diff --git a/core/msg_network.js b/core/msg_network.js index 9e0813f4..890d1bcf 100644 --- a/core/msg_network.js +++ b/core/msg_network.js @@ -38,17 +38,17 @@ function startup(cb) { function shutdown(cb) { async.each( - msgNetworkModules, + msgNetworkModules, (msgNetModule, next) => { msgNetModule.shutdown( () => { return next(); }); - }, + }, () => { msgNetworkModules = []; return cb(null); } - ); + ); } function recordMessage(message, cb) { @@ -59,7 +59,7 @@ function recordMessage(message, cb) { // async.each(msgNetworkModules, (modInst, next) => { modInst.record(message); - next(); + next(); }, err => { cb(err); }); diff --git a/core/msg_scan_toss_module.js b/core/msg_scan_toss_module.js index 8172d77f..9b3598c1 100644 --- a/core/msg_scan_toss_module.js +++ b/core/msg_scan_toss_module.js @@ -13,12 +13,12 @@ function MessageScanTossModule() { require('util').inherits(MessageScanTossModule, PluginModule); MessageScanTossModule.prototype.startup = function(cb) { - cb(null); + return cb(null); }; MessageScanTossModule.prototype.shutdown = function(cb) { - cb(null); + return cb(null); }; -MessageScanTossModule.prototype.record = function(message) { +MessageScanTossModule.prototype.record = function(/*message*/) { }; \ No newline at end of file diff --git a/core/multi_line_edit_text_view.js b/core/multi_line_edit_text_view.js index 68d8b3d6..bc73e903 100644 --- a/core/multi_line_edit_text_view.js +++ b/core/multi_line_edit_text_view.js @@ -4,7 +4,6 @@ const View = require('./view.js').View; const strUtil = require('./string_util.js'); const ansi = require('./ansi_term.js'); -const colorCodes = require('./color_codes.js'); const wordWrapText = require('./word_wrap.js').wordWrapText; const ansiPrep = require('./ansi_prep.js'); @@ -12,11 +11,11 @@ const assert = require('assert'); const _ = require('lodash'); // :TODO: Determine CTRL-* keys for various things - // See http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/bansi.txt - // http://wiki.synchro.net/howto:editor:slyedit#edit_mode - // http://sublime-text-unofficial-documentation.readthedocs.org/en/latest/reference/keyboard_shortcuts_win.html +// See http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/bansi.txt +// http://wiki.synchro.net/howto:editor:slyedit#edit_mode +// http://sublime-text-unofficial-documentation.readthedocs.org/en/latest/reference/keyboard_shortcuts_win.html - /* Mystic +/* Mystic [^B] Reformat Paragraph [^O] Show this help file [^I] Insert tab space [^Q] Enter quote mode [^K] Cut current line of text [^V] Toggle insert/overwrite @@ -179,8 +178,8 @@ function MultiLineEditTextView(options) { for(let i = startIndex; i < endIndex; ++i) { //${self.getSGRFor('text')} - self.client.term.write( - `${ansi.goto(absPos.row++, absPos.col)}${self.getRenderText(i)}`, + self.client.term.write( + `${ansi.goto(absPos.row++, absPos.col)}${self.getRenderText(i)}`, false // convertLineFeeds ); } @@ -268,7 +267,7 @@ function MultiLineEditTextView(options) { if(remain > 0) { text += ' '.repeat(remain + 1); -// text += new Array(remain + 1).join(' '); + // text += new Array(remain + 1).join(' '); } return text; @@ -291,7 +290,7 @@ function MultiLineEditTextView(options) { lines.forEach(line => { text += line.text.replace(re, '\t'); - + if(options.forceLineTerms || (eolMarker && line.eol)) { text += eolMarker; } @@ -459,7 +458,7 @@ function MultiLineEditTextView(options) { self.getRenderText(index).slice(self.cursorPos.col - c.length) + ansi.goto(absPos.row, absPos.col) + ansi.showCursor(), false - ); + ); } }; @@ -502,7 +501,7 @@ function MultiLineEditTextView(options) { } return wordWrapText( - s, + s, { width : width, tabHandling : tabHandling || 'expand', @@ -1122,19 +1121,19 @@ MultiLineEditTextView.prototype.getData = function(options = { forceLineTerms : MultiLineEditTextView.prototype.setPropertyValue = function(propName, value) { switch(propName) { - case 'mode' : + case 'mode' : this.mode = value; if('preview' === value && !this.specialKeyMap.next) { this.specialKeyMap.next = [ 'tab' ]; - } + } break; - case 'autoScroll' : + case 'autoScroll' : this.autoScroll = value; break; case 'tabSwitchesView' : - this.tabSwitchesView = value; + this.tabSwitchesView = value; this.specialKeyMap.next = this.specialKeyMap.next || []; this.specialKeyMap.next.push('tab'); break; diff --git a/core/new_scan.js b/core/new_scan.js index f3e851fb..b088e47f 100644 --- a/core/new_scan.js +++ b/core/new_scan.js @@ -25,8 +25,8 @@ exports.moduleInfo = { * :TODO: * * User configurable new scan: Area selection (avail from messages area) (sep module) * * Add status TL/VM (either/both should update if present) - * * - + * * + */ const MciCodeIds = { @@ -37,7 +37,7 @@ const MciCodeIds = { const Steps = { MessageConfs : 'messageConferences', FileBase : 'fileBase', - + Finished : 'finished', }; @@ -53,7 +53,7 @@ exports.getModule = class NewScanModule extends MenuModule { // :TODO: Make this conf/area specific: const config = this.menuConfig.config; - this.scanStartFmt = config.scanStartFmt || 'Scanning {confName} - {areaName}...'; + this.scanStartFmt = config.scanStartFmt || 'Scanning {confName} - {areaName}...'; this.scanFinishNoneFmt = config.scanFinishNoneFmt || 'Nothing new'; this.scanFinishNewFmt = config.scanFinishNewFmt || '{count} entries found'; this.scanCompleteMsg = config.scanCompleteMsg || 'Finished newscan'; @@ -62,16 +62,16 @@ exports.getModule = class NewScanModule extends MenuModule { updateScanStatus(statusText) { this.setViewText('allViews', MciCodeIds.ScanStatusLabel, statusText); } - + newScanMessageConference(cb) { - // lazy init + // lazy init if(!this.sortedMessageConfs) { - const getAvailOpts = { includeSystemInternal : true }; // find new private messages, bulletins, etc. + const getAvailOpts = { includeSystemInternal : true }; // find new private messages, bulletins, etc. this.sortedMessageConfs = _.map(msgArea.getAvailableMessageConferences(this.client, getAvailOpts), (v, k) => { return { confTag : k, - conf : v, + conf : v, }; }); @@ -91,27 +91,27 @@ exports.getModule = class NewScanModule extends MenuModule { this.currentScanAux.conf = this.currentScanAux.conf || 0; this.currentScanAux.area = this.currentScanAux.area || 0; } - + const currentConf = this.sortedMessageConfs[this.currentScanAux.conf]; this.newScanMessageArea(currentConf, () => { if(this.sortedMessageConfs.length > this.currentScanAux.conf + 1) { - this.currentScanAux.conf += 1; + this.currentScanAux.conf += 1; this.currentScanAux.area = 0; - + return this.newScanMessageConference(cb); // recursive to next conf } this.updateScanStatus(this.scanCompleteMsg); return cb(Errors.DoesNotExist('No more conferences')); - }); + }); } - + newScanMessageArea(conf, cb) { - // :TODO: it would be nice to cache this - must be done by conf! + // :TODO: it would be nice to cache this - must be done by conf! const sortedAreas = msgArea.getSortedAvailMessageAreasByConfTag(conf.confTag, { client : this.client } ); const currentArea = sortedAreas[this.currentScanAux.area]; - + // // Scan and update index until we find something. If results are found, // we'll goto the list module & show them. @@ -207,20 +207,20 @@ exports.getModule = class NewScanModule extends MenuModule { performScanCurrentStep(cb) { switch(this.currentStep) { - case Steps.MessageConfs : - this.newScanMessageConference( () => { + case Steps.MessageConfs : + this.newScanMessageConference( () => { this.currentStep = Steps.FileBase; return this.performScanCurrentStep(cb); }); break; - + case Steps.FileBase : this.newScanFileBase( () => { this.currentStep = Steps.Finished; - return this.performScanCurrentStep(cb); + return this.performScanCurrentStep(cb); }); break; - + default : return cb(null); } } @@ -241,7 +241,7 @@ exports.getModule = class NewScanModule extends MenuModule { // :TODO: display scan step/etc. - async.series( + async.series( [ function loadFromConfig(callback) { const loadOpts = { diff --git a/core/nua.js b/core/nua.js index 7939e739..61dbeb62 100644 --- a/core/nua.js +++ b/core/nua.js @@ -22,10 +22,10 @@ const MciViewIds = { }; exports.getModule = class NewUserAppModule extends MenuModule { - + constructor(options) { super(options); - + const self = this; this.menuMethods = { @@ -40,7 +40,7 @@ exports.getModule = class NewUserAppModule extends MenuModule { viewValidationListener : function(err, cb) { const errMsgView = self.viewControllers.menu.getView(MciViewIds.errMsg); let newFocusId; - + if(err) { errMsgView.setText(err.message); err.view.clearText(); @@ -67,14 +67,14 @@ exports.getModule = class NewUserAppModule extends MenuModule { // // We have to disable ACS checks for initial default areas as the user is not yet ready - // + // let confTag = messageArea.getDefaultMessageConferenceTag(self.client, true); // true=disableAcsCheck let areaTag = messageArea.getDefaultMessageAreaTagByConfTag(self.client, confTag, true); // true=disableAcsCheck // can't store undefined! confTag = confTag || ''; areaTag = areaTag || ''; - + newUser.properties = { real_name : formData.value.realName, birthdate : new Date(Date.parse(formData.value.birthdate)).toISOString(), // :TODO: Use moment & explicit ISO string format @@ -84,12 +84,12 @@ exports.getModule = class NewUserAppModule extends MenuModule { email_address : formData.value.email, web_address : formData.value.web, account_created : new Date().toISOString(), // :TODO: Use moment & explicit ISO string format - + message_conf_tag : confTag, message_area_tag : areaTag, term_height : self.client.term.termHeight, - term_width : self.client.term.termWidth, + term_width : self.client.term.termWidth, // :TODO: Other defaults // :TODO: should probably have a place to create defaults/etc. @@ -100,7 +100,7 @@ exports.getModule = class NewUserAppModule extends MenuModule { } else { newUser.properties.theme_id = Config.defaults.theme; } - + // :TODO: User.create() should validate email uniqueness! newUser.create(formData.value.password, err => { if(err) { diff --git a/core/onelinerz.js b/core/onelinerz.js index 9e89addf..65599ba9 100644 --- a/core/onelinerz.js +++ b/core/onelinerz.js @@ -20,7 +20,7 @@ const async = require('async'); const _ = require('lodash'); const moment = require('moment'); -/* +/* Module :TODO: * Add pipe code support - override max length & monitor *display* len as user types in order to allow for actual display len with color @@ -73,7 +73,7 @@ exports.getModule = class OnelinerzModule extends MenuModule { self.client.log.warn( { error : err.message }, 'Failed saving oneliner'); } - self.clearAddForm(); + self.clearAddForm(); return self.displayViewScreen(true, cb); // true=cls }); @@ -89,7 +89,7 @@ exports.getModule = class OnelinerzModule extends MenuModule { } }; } - + initSequence() { const self = this; async.series( @@ -136,7 +136,7 @@ exports.getModule = class OnelinerzModule extends MenuModule { function initOrRedrawViewController(artData, callback) { if(_.isUndefined(self.viewControllers.add)) { const vc = self.addViewController( - 'view', + 'view', new ViewController( { client : self.client, formId : FormIds.View } ) ); @@ -149,7 +149,7 @@ exports.getModule = class OnelinerzModule extends MenuModule { return vc.loadFromMenuConfig(loadOpts, callback); } else { self.viewControllers.view.setFocus(true); - self.viewControllers.view.getView(MciViewIds.ViewForm.AddPrompt).redraw(); + self.viewControllers.view.getView(MciViewIds.ViewForm.AddPrompt).redraw(); return callback(null); } }, @@ -216,7 +216,7 @@ exports.getModule = class OnelinerzModule extends MenuModule { [ function clearAndDisplayArt(callback) { self.viewControllers.view.setFocus(false); - self.client.term.rawWrite(ansi.resetScreen()); + self.client.term.rawWrite(ansi.resetScreen()); theme.displayThemedAsset( self.menuConfig.config.art.add, @@ -230,7 +230,7 @@ exports.getModule = class OnelinerzModule extends MenuModule { function initOrRedrawViewController(artData, callback) { if(_.isUndefined(self.viewControllers.add)) { const vc = self.addViewController( - 'add', + 'add', new ViewController( { client : self.client, formId : FormIds.Add } ) ); @@ -269,7 +269,7 @@ exports.getModule = class OnelinerzModule extends MenuModule { [ function openDatabase(callback) { self.db = getTransactionDatabase(new sqlite3.Database( - getModDatabasePath(exports.moduleInfo), + getModDatabasePath(exports.moduleInfo), err => { return callback(err); } @@ -284,10 +284,10 @@ exports.getModule = class OnelinerzModule extends MenuModule { oneliner VARCHAR NOT NULL, timestamp DATETIME NOT NULL );` - , - err => { - return callback(err); - }); + , + err => { + return callback(err); + }); } ], err => { @@ -327,7 +327,7 @@ exports.getModule = class OnelinerzModule extends MenuModule { err => { return cb(err); } - ); + ); } beforeArt(cb) { diff --git a/core/plugin_module.js b/core/plugin_module.js index 31ba6f01..da9410b0 100644 --- a/core/plugin_module.js +++ b/core/plugin_module.js @@ -3,5 +3,5 @@ exports.PluginModule = PluginModule; -function PluginModule(options) { +function PluginModule(/*options*/) { } diff --git a/core/predefined_mci.js b/core/predefined_mci.js index 7fe921b3..47370a66 100644 --- a/core/predefined_mci.js +++ b/core/predefined_mci.js @@ -92,7 +92,7 @@ const PREDEFINED_MCI_GENERATORS = { ST : function serverName(client) { return client.session.serverName; }, FN : function activeFileBaseFilterName(client) { const activeFilter = FileBaseFilters.getActiveFilter(client); - return activeFilter ? activeFilter.name : ''; + return activeFilter ? activeFilter.name : ''; }, DN : function userNumDownloads(client) { return userStatAsString(client, 'dl_total_count', 0); }, // Obv/2 DK : function userByteDownload(client) { // Obv/2 uses DK=downloaded Kbytes @@ -160,7 +160,7 @@ const PREDEFINED_MCI_GENERATORS = { }, OA : function systemArchitecture() { return os.arch(); }, - + SC : function systemCpuModel() { // // Clean up CPU strings a bit for better display @@ -190,7 +190,7 @@ const PREDEFINED_MCI_GENERATORS = { // System File Base, Up/Download Info // // :TODO: DD - Today's # of downloads (iNiQUiTY) - // + // SD : function systemNumDownloads() { return sysStatAsString('dl_total_count', 0); }, SO : function systemByteDownload() { const byteSize = StatLog.getSystemStatNum('dl_total_bytes'); @@ -221,7 +221,7 @@ const PREDEFINED_MCI_GENERATORS = { // -> Include FTN/etc. // :TODO: LC - name of last caller to system (Obv/2) // :TODO: TZ - Average *system* post/call ratio (iNiQUiTY) - + // // Special handling for XY diff --git a/core/rumorz.js b/core/rumorz.js index b83853f0..da1ab5f6 100644 --- a/core/rumorz.js +++ b/core/rumorz.js @@ -52,9 +52,9 @@ exports.getModule = class RumorzModule extends MenuModule { addEntry : (formData, extraArgs, cb) => { if(_.isString(formData.value.rumor) && renderStringLength(formData.value.rumor) > 0) { const rumor = formData.value.rumor.trim(); // remove any trailing ws - + StatLog.appendSystemLogEntry(STATLOG_KEY_RUMORZ, rumor, StatLog.KeepDays.Forever, StatLog.KeepType.Forever, () => { - this.clearAddForm(); + this.clearAddForm(); return this.displayViewScreen(true, cb); // true=cls }); } else { @@ -77,7 +77,7 @@ exports.getModule = class RumorzModule extends MenuModule { const previewView = this.viewControllers.add.getView(MciCodeIds.AddForm.EntryPreview); newEntryView.setText(''); - + // preview is optional if(previewView) { previewView.setText(''); @@ -130,7 +130,7 @@ exports.getModule = class RumorzModule extends MenuModule { function initOrRedrawViewController(artData, callback) { if(_.isUndefined(self.viewControllers.add)) { const vc = self.addViewController( - 'view', + 'view', new ViewController( { client : self.client, formId : FormIds.View } ) ); @@ -143,7 +143,7 @@ exports.getModule = class RumorzModule extends MenuModule { return vc.loadFromMenuConfig(loadOpts, callback); } else { self.viewControllers.view.setFocus(true); - self.viewControllers.view.getView(MciCodeIds.ViewForm.AddPrompt).redraw(); + self.viewControllers.view.getView(MciCodeIds.ViewForm.AddPrompt).redraw(); return callback(null); } }, @@ -186,7 +186,7 @@ exports.getModule = class RumorzModule extends MenuModule { [ function clearAndDisplayArt(callback) { self.viewControllers.view.setFocus(false); - self.client.term.rawWrite(resetScreen()); + self.client.term.rawWrite(resetScreen()); theme.displayThemedAsset( self.config.art.add, @@ -200,7 +200,7 @@ exports.getModule = class RumorzModule extends MenuModule { function initOrRedrawViewController(artData, callback) { if(_.isUndefined(self.viewControllers.add)) { const vc = self.addViewController( - 'add', + 'add', new ViewController( { client : self.client, formId : FormIds.Add } ) ); @@ -220,7 +220,7 @@ exports.getModule = class RumorzModule extends MenuModule { }, function initPreviewUpdates(callback) { const previewView = self.viewControllers.add.getView(MciCodeIds.AddForm.EntryPreview); - const entryView = self.viewControllers.add.getView(MciCodeIds.AddForm.NewEntry); + const entryView = self.viewControllers.add.getView(MciCodeIds.AddForm.NewEntry); if(previewView) { let timerId; entryView.on('key press', () => { @@ -230,7 +230,7 @@ exports.getModule = class RumorzModule extends MenuModule { if(focused === entryView) { previewView.setText(entryView.getData()); focused.setFocus(true); - } + } }, 500); }); } diff --git a/core/sauce.js b/core/sauce.js index 295a6069..b976450b 100644 --- a/core/sauce.js +++ b/core/sauce.js @@ -8,7 +8,9 @@ exports.readSAUCE = readSAUCE; const SAUCE_SIZE = 128; const SAUCE_ID = new Buffer([0x53, 0x41, 0x55, 0x43, 0x45]); // 'SAUCE' -const COMNT_ID = new Buffer([0x43, 0x4f, 0x4d, 0x4e, 0x54]); // 'COMNT' + +// :TODO read comments +//const COMNT_ID = new Buffer([0x43, 0x4f, 0x4d, 0x4e, 0x54]); // 'COMNT' exports.SAUCE_SIZE = SAUCE_SIZE; // :TODO: SAUCE should be a class @@ -51,7 +53,7 @@ function readSAUCE(data, cb) { if(!SAUCE_ID.equals(vars.id)) { return cb(new Error('No SAUCE record present')); - } + } var ver = iconv.decode(vars.version, 'cp437'); @@ -137,7 +139,7 @@ var SAUCE_FONT_TO_ENCODING_HINT = { }; ['437', '720', '737', '775', '819', '850', '852', '855', '857', '858', -'860', '861', '862', '863', '864', '865', '866', '869', '872'].forEach(function onPage(page) { + '860', '861', '862', '863', '864', '865', '866', '869', '872'].forEach(function onPage(page) { var codec = 'cp' + page; SAUCE_FONT_TO_ENCODING_HINT['IBM EGA43 ' + page] = codec; SAUCE_FONT_TO_ENCODING_HINT['IBM EGA ' + page] = codec; diff --git a/core/scanner_tossers/ftn_bso.js b/core/scanner_tossers/ftn_bso.js index 8da71d02..20ab435f 100644 --- a/core/scanner_tossers/ftn_bso.js +++ b/core/scanner_tossers/ftn_bso.js @@ -1213,7 +1213,30 @@ function FTNMessageScanTossModule() { User.getUserIdAndNameByLookup(lookupName, (err, localToUserId, localUserName) => { if(err) { - return callback(Errors.DoesNotExist(`Could not get local user ID for "${message.toUserName}": ${err.message}`)); + // + // Couldn't find a local username. If the toUserName itself is a FTN address + // we can only assume the message is to the +op, else we'll have to fail. + // + const toUserNameAsAddress = Address.fromString(message.toUserName); + if(toUserNameAsAddress.isValid()) { + + Log.info( + { toUserName : message.toUserName, fromUserName : message.fromUserName }, + 'No local "to" username for FTN message. Appears to be a FTN address only; assuming addressed to SysOp' + ); + + User.getUserName(User.RootUserID, (err, sysOpUserName) => { + if(err) { + return callback(Errors.UnexpectedState('Failed to get SysOp user information')); + } + + message.meta.System[Message.SystemMetaNames.LocalToUserID] = User.RootUserID; + message.toUserName = sysOpUserName; + return callback(null); + }); + } else { + return callback(Errors.DoesNotExist(`Could not get local user ID for "${message.toUserName}": ${err.message}`)); + } } // we do this after such that error cases can be preseved above diff --git a/core/set_newscan_date.js b/core/set_newscan_date.js index 0e29e999..efcb1f19 100644 --- a/core/set_newscan_date.js +++ b/core/set_newscan_date.js @@ -43,7 +43,7 @@ exports.getModule = class SetNewScanDate extends MenuModule { const config = this.menuConfig.config; this.target = config.target || 'message'; - this.scanDateFormat = config.scanDateFormat || 'YYYYMMDD'; + this.scanDateFormat = config.scanDateFormat || 'YYYYMMDD'; this.menuMethods = { scanDateSubmit : (formData, extraArgs, cb) => { @@ -232,7 +232,7 @@ exports.getModule = class SetNewScanDate extends MenuModule { const scanDateView = vc.getView(MciViewIds.main.scanDate); // :TODO: MaskTextEditView needs some love: If setText() with input that matches the mask, we should ignore the non-mask chars! Hack in place for now - const scanDateFormat = self.scanDateFormat.replace(/[\/\-. ]/g, ''); + const scanDateFormat = self.scanDateFormat.replace(/[/\-. ]/g, ''); scanDateView.setText(today.format(scanDateFormat)); if('message' === self.target) { diff --git a/core/spinner_menu_view.js b/core/spinner_menu_view.js index 65ac10af..e9145662 100644 --- a/core/spinner_menu_view.js +++ b/core/spinner_menu_view.js @@ -1,13 +1,12 @@ /* jslint node: true */ 'use strict'; -var MenuView = require('./menu_view.js').MenuView; -var ansi = require('./ansi_term.js'); -var strUtil = require('./string_util.js'); +const MenuView = require('./menu_view.js').MenuView; +const ansi = require('./ansi_term.js'); +const strUtil = require('./string_util.js'); -var util = require('util'); -var assert = require('assert'); -var _ = require('lodash'); +const util = require('util'); +const assert = require('assert'); exports.SpinnerMenuView = SpinnerMenuView; @@ -16,7 +15,7 @@ function SpinnerMenuView(options) { options.cursor = options.cursor || 'hide'; MenuView.call(this, options); - + var self = this; /* @@ -29,7 +28,7 @@ function SpinnerMenuView(options) { //assert(!self.positionCacheExpired); assert(this.focusedItemIndex >= 0 && this.focusedItemIndex <= self.items.length); - + self.drawItem(this.focusedItemIndex); }; @@ -66,19 +65,19 @@ SpinnerMenuView.prototype.setFocus = function(focused) { SpinnerMenuView.prototype.setFocusItemIndex = function(index) { SpinnerMenuView.super_.prototype.setFocusItemIndex.call(this, index); // sets this.focusedItemIndex - + this.updateSelection(); // will redraw }; SpinnerMenuView.prototype.onKeyPress = function(ch, key) { if(key) { - if(this.isKeyMapped('up', key.name)) { + if(this.isKeyMapped('up', key.name)) { if(0 === this.focusedItemIndex) { this.focusedItemIndex = this.items.length - 1; } else { this.focusedItemIndex--; } - + this.updateSelection(); return; } else if(this.isKeyMapped('down', key.name)) { @@ -87,7 +86,7 @@ SpinnerMenuView.prototype.onKeyPress = function(ch, key) { } else { this.focusedItemIndex++; } - + this.updateSelection(); return; } diff --git a/core/stat_log.js b/core/stat_log.js index d6a53d28..edb2d98c 100644 --- a/core/stat_log.js +++ b/core/stat_log.js @@ -10,14 +10,14 @@ const moment = require('moment'); /* System Event Log & Stats ------------------------ - + System & user specific: * Events for generating various statistics, logs such as last callers, etc. * Stats such as counters User specific stats are simply an alternate interface to user properties, while system wide entries are handled on their own. Both are read accessible non-blocking - making them easily available for MCI codes for example. + making them easily available for MCI codes for example. */ class StatLog { constructor() { @@ -66,7 +66,7 @@ class StatLog { TimestampDesc : 'timestamp_desc', Random : 'random', }; - } + } setNonPeristentSystemStat(statName, statValue) { this.systemStats[statName] = statValue; @@ -139,7 +139,7 @@ class StatLog { return cb(new Error(`Value for ${statName} is not a number!`)); } - newValue += incrementBy; + newValue += incrementBy; } else { newValue = incrementBy; } @@ -201,19 +201,19 @@ class StatLog { } } ); - break; + break; case 'forever' : default : // nop break; - } + } } ); } getSystemLogEntries(logName, order, limit, cb) { - let sql = + let sql = `SELECT timestamp, log_value FROM system_event_log WHERE log_name = ?`; @@ -228,7 +228,7 @@ class StatLog { sql += ' ORDER BY timestamp DESC'; break; - case 'random' : + case 'random' : sql += ' ORDER BY RANDOM()'; } @@ -279,7 +279,7 @@ class StatLog { ); } ); - } + } } module.exports = new StatLog(); diff --git a/core/stats.js b/core/stats.js deleted file mode 100644 index ecc472de..00000000 --- a/core/stats.js +++ /dev/null @@ -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); - } - ); -} diff --git a/core/status_bar_view.js b/core/status_bar_view.js deleted file mode 100644 index ed47ca7d..00000000 --- a/core/status_bar_view.js +++ /dev/null @@ -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 } ); - } - }); - -}; - diff --git a/core/string_format.js b/core/string_format.js index 7fb7109a..eba715d5 100644 --- a/core/string_format.js +++ b/core/string_format.js @@ -5,7 +5,7 @@ const EnigError = require('./enig_error.js').EnigError; const { pad, - stylizeString, + stylizeString, renderStringLength, renderSubstr, formatByteSize, formatByteSizeAbbr, @@ -172,15 +172,15 @@ function formatNumberHelper(n, precision, type) { case 'b' : return n.toString(2); case 'o' : return n.toString(8); case 'x' : return n.toString(16); - case 'e' : return n.toExponential(precision).replace(FormatNumRegExp.ExponentRep, '$&0'); - case 'f' : return n.toFixed(precision); + case 'e' : return n.toExponential(precision).replace(FormatNumRegExp.ExponentRep, '$&0'); + case 'f' : return n.toFixed(precision); case 'g' : // we don't want useless trailing zeros. parseFloat -> back to string fixes this for us return parseFloat(n.toPrecision(precision || 1)).toString(); case '%' : return formatNumberHelper(n * 100, precision, 'f') + '%'; case '' : return formatNumberHelper(n, precision, 'd'); - + default : throw new ValueError(`Unknown format code "${type}" for object of type 'float'`); } @@ -207,7 +207,7 @@ function formatNumber(value, tokens) { if('' !== tokens.precision) { throw new ValueError('Precision not allowed in integer format specifier'); - } + } } else if( [ 'e', 'E', 'f', 'F', 'g', 'G', '%' ].indexOf(type) > - 1) { if(tokens['#']) { throw new ValueError('Alternate form (#) not allowed in float format specifier'); @@ -215,7 +215,7 @@ function formatNumber(value, tokens) { } const s = formatNumberHelper(Math.abs(value), Number(tokens.precision || 6), type); - const sign = value < 0 || 1 / value < 0 ? + const sign = value < 0 || 1 / value < 0 ? '-' : '-' === tokens.sign ? '' : tokens.sign; @@ -223,7 +223,7 @@ function formatNumber(value, tokens) { if(tokens[',']) { const match = /^(\d*)(.*)$/.exec(s); - const separated = match[1].replace(/.(?=(...)+$)/g, '$&,') + match[2]; + const separated = match[1].replace(/.(?=(...)+$)/g, '$&,') + match[2]; if('=' !== align) { return pad(sign + separated, width, fill, getPadAlign(align)); @@ -246,7 +246,7 @@ function formatNumber(value, tokens) { if(0 === width) { return sign + prefix + s; - } + } if('=' === align) { return sign + prefix + pad(s, width - sign.length - prefix.length, fill, getPadAlign('>')); @@ -272,9 +272,9 @@ const transformers = { styleL33t : (s) => stylizeString(s, 'l33t'), // :TODO: - // toMegs(), toKilobytes(), ... - // toList(), toCommaList(), - + // toMegs(), toKilobytes(), ... + // toList(), toCommaList(), + sizeWithAbbr : (n) => formatByteSize(n, true, 2), sizeWithoutAbbr : (n) => formatByteSize(n, false, 2), sizeAbbr : (n) => formatByteSizeAbbr(n), @@ -293,14 +293,14 @@ function transformValue(transformerName, value) { } // :TODO: Use explicit set of chars for paths & function/transforms such that } is allowed as fill/etc. -const REGEXP_BASIC_FORMAT = /{([^.!:}]+(?:\.[^.!:}]+)*)(?:\!([^:}]+))?(?:\:([^}]+))?}/g; +const REGEXP_BASIC_FORMAT = /{([^.!:}]+(?:\.[^.!:}]+)*)(?:!([^:}]+))?(?::([^}]+))?}/g; function getValue(obj, path) { const value = _.get(obj, path); if(!_.isUndefined(value)) { return _.isFunction(value) ? value() : value; } - + throw new KeyError(quote(path)); } @@ -350,7 +350,7 @@ module.exports = function format(fmt, obj) { // remainder if(pos < fmt.length) { out += fmt.slice(pos); - } + } - return out; + return out; }; diff --git a/core/string_util.js b/core/string_util.js index 238aeeee..a4544754 100644 --- a/core/string_util.js +++ b/core/string_util.js @@ -3,7 +3,6 @@ // ENiGMA½ const miscUtil = require('./misc_util.js'); -const ANSIEscapeParser = require('./ansi_escape_parser.js').ANSIEscapeParser; const ANSI = require('./ansi_term.js'); // deps @@ -53,12 +52,12 @@ function stylizeString(s, style) { switch(style) { // None/normal case 'normal' : - case 'N' : + case 'N' : return s; // UPPERCASE - case 'upper' : - case 'U' : + case 'upper' : + case 'U' : return s.toUpperCase(); // lowercase @@ -107,8 +106,8 @@ function stylizeString(s, style) { return stylized; // Small i's: DEMENTiA - case 'small i' : - case 'i' : + case 'small i' : + case 'i' : return s.toUpperCase().replace(/I/g, 'i'); // mIxeD CaSE (random upper/lower) @@ -128,7 +127,7 @@ function stylizeString(s, style) { case '3' : for(i = 0; i < len; ++i) { c = SIMPLE_ELITE_MAP[s[i].toLowerCase()]; - stylized += c || s[i]; + stylized += c || s[i]; } return stylized; } @@ -147,11 +146,11 @@ function pad(s, len, padChar, dir, stringSGR, padSGR, useRenderLen) { useRenderLen = miscUtil.valueWithDefault(useRenderLen, true); const renderLen = useRenderLen ? renderStringLength(s) : s.length; - const padlen = len >= renderLen ? len - renderLen : 0; + const padlen = len >= renderLen ? len - renderLen : 0; switch(dir) { case 'L' : - case 'left' : + case 'left' : s = padSGR + new Array(padlen).join(padChar) + stringSGR + s; break; @@ -162,10 +161,10 @@ function pad(s, len, padChar, dir, stringSGR, padSGR, useRenderLen) { const right = Math.ceil(padlen / 2); const left = padlen - right; s = padSGR + new Array(left + 1).join(padChar) + stringSGR + s + padSGR + new Array(right + 1).join(padChar); - } + } break; - case 'R' : + case 'R' : case 'right' : s = stringSGR + s + padSGR + new Array(padlen).join(padChar); break; @@ -184,7 +183,7 @@ function replaceAt(s, n, t) { return s.substring(0, n) + t + s.substring(n + 1); } -const RE_NON_PRINTABLE = +const RE_NON_PRINTABLE = /[\0-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/; // eslint-disable-line no-control-regex function isPrintable(s) { @@ -198,11 +197,6 @@ function isPrintable(s) { return !RE_NON_PRINTABLE.test(s); } -function stringLength(s) { - // :TODO: See https://mathiasbynens.be/notes/javascript-unicode - return s.length; -} - function stripAllLineFeeds(s) { return s.replace(/\r?\n|[\r\u2028\u2029]/g, ''); } @@ -256,7 +250,7 @@ function renderSubstr(str, start, length) { match = re.exec(str); if(match) { - if(match.index > pos) { + if(match.index > pos) { s = str.slice(pos + start, Math.min(match.index, pos + (length - renderLen))); start = 0; // start offset applies only once out += s; @@ -269,7 +263,7 @@ function renderSubstr(str, start, length) { // remainder if(pos + start < str.length && renderLen < length) { - out += str.slice(pos + start, (pos + start + (length - renderLen))); + out += str.slice(pos + start, (pos + start + (length - renderLen))); //out += str.slice(pos + start, Math.max(1, pos + (length - renderLen - 1))); } @@ -277,7 +271,7 @@ function renderSubstr(str, start, length) { } // -// Method to return the "rendered" length taking into account Pipe and ANSI color codes. +// Method to return the "rendered" length taking into account Pipe and ANSI color codes. // // We additionally account for ANSI *forward* movement ESC sequences // in the form of ESC[C where is the "go forward" character count. @@ -291,40 +285,40 @@ function renderStringLength(s) { const re = ANSI_OR_PIPE_REGEXP; re.lastIndex = 0; // we recycle the rege; reset - + // // Loop counting only literal (non-control) sequences // paying special attention to ESC[C which means forward - // + // do { pos = re.lastIndex; m = re.exec(s); - + if(m) { if(m.index > pos) { len += s.slice(pos, m.index).length; } - + if('C' === m[3]) { // ESC[C is foward/right len += parseInt(m[2], 10) || 0; } - } + } } while(0 !== re.lastIndex); - + if(pos < s.length) { len += s.slice(pos).length; } - + return len; } -const BYTE_SIZE_ABBRS = [ 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' ]; // :) +const BYTE_SIZE_ABBRS = [ 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' ]; // :) function formatByteSizeAbbr(byteSize) { if(0 === byteSize) { return BYTE_SIZE_ABBRS[0]; // B } - + return BYTE_SIZE_ABBRS[Math.floor(Math.log(byteSize) / Math.log(1024))]; } @@ -332,7 +326,7 @@ function formatByteSize(byteSize, withAbbr = false, decimals = 2) { const i = 0 === byteSize ? byteSize : Math.floor(Math.log(byteSize) / Math.log(1024)); let result = parseFloat((byteSize / Math.pow(1024, i)).toFixed(decimals)); if(withAbbr) { - result += ` ${BYTE_SIZE_ABBRS[i]}`; + result += ` ${BYTE_SIZE_ABBRS[i]}`; } return result; } @@ -351,7 +345,7 @@ function formatCount(count, withAbbr = false, decimals = 2) { const i = 0 === count ? count : Math.floor(Math.log(count) / Math.log(1000)); let result = parseFloat((count / Math.pow(1000, i)).toFixed(decimals)); if(withAbbr) { - result += `${COUNT_ABBRS[i]}`; + result += `${COUNT_ABBRS[i]}`; } return result; } @@ -359,7 +353,7 @@ function formatCount(count, withAbbr = false, decimals = 2) { // :TODO: See notes in word_wrap.js about need to consolidate the various ANSI related RegExp's //const REGEXP_ANSI_CONTROL_CODES = /(\x1b\x5b)([\?=;0-9]*?)([0-9A-ORZcf-npsu=><])/g; -const REGEXP_ANSI_CONTROL_CODES = /(?:\x1b\x5b)([\?=;0-9]*?)([A-ORZcf-npsu=><])/g; // eslint-disable-line no-control-regex +const REGEXP_ANSI_CONTROL_CODES = /(?:\x1b\x5b)([?=;0-9]*?)([A-ORZcf-npsu=><])/g; // eslint-disable-line no-control-regex const ANSI_OPCODES_ALLOWED_CLEAN = [ //'A', 'B', // up, down //'C', 'D', // right, left @@ -370,17 +364,17 @@ function cleanControlCodes(input, options) { let m; let pos; let cleaned = ''; - + options = options || {}; - + // // Loop through |input| adding only allowed ESC // sequences and literals to |cleaned| - // + // do { pos = REGEXP_ANSI_CONTROL_CODES.lastIndex; m = REGEXP_ANSI_CONTROL_CODES.exec(input); - + if(m) { if(m.index > pos) { cleaned += input.slice(pos, m.index); @@ -394,205 +388,17 @@ function cleanControlCodes(input, options) { cleaned += m[0]; } } - + } while(0 !== REGEXP_ANSI_CONTROL_CODES.lastIndex); - + // remainder if(pos < input.length) { cleaned += input.slice(pos); } - + return cleaned; } -function prepAnsi(input, options, cb) { - if(!input) { - return cb(null, ''); - } - - options.termWidth = options.termWidth || 80; - options.termHeight = options.termHeight || 25; - options.cols = options.cols || options.termWidth || 80; - options.rows = options.rows || options.termHeight || 'auto'; - options.startCol = options.startCol || 1; - options.exportMode = options.exportMode || false; - - const canvas = Array.from( { length : 'auto' === options.rows ? 25 : options.rows }, () => Array.from( { length : options.cols}, () => new Object() ) ); - const parser = new ANSIEscapeParser( { termHeight : options.termHeight, termWidth : options.termWidth } ); - - const state = { - row : 0, - col : 0, - }; - - let lastRow = 0; - - function ensureRow(row) { - if(Array.isArray(canvas[row])) { - return; - } - - canvas[row] = Array.from( { length : options.cols}, () => new Object() ); - } - - parser.on('position update', (row, col) => { - state.row = row - 1; - state.col = col - 1; - - lastRow = Math.max(state.row, lastRow); - }); - - parser.on('literal', literal => { - // - // CR/LF are handled for 'position update'; we don't need the chars themselves - // - literal = literal.replace(/\r?\n|[\r\u2028\u2029]/g, ''); - - for(let c of literal) { - if(state.col < options.cols && ('auto' === options.rows || state.row < options.rows)) { - ensureRow(state.row); - - canvas[state.row][state.col].char = c; - - if(state.sgr) { - canvas[state.row][state.col].sgr = state.sgr; - state.sgr = null; - } - } - - state.col += 1; - } - }); - - parser.on('control', (match, opCode) => { - // - // Movement is handled via 'position update', so we really only care about - // display opCodes - // - switch(opCode) { - case 'm' : - state.sgr = (state.sgr || '') + match; - break; - - default : - break; - } - }); - - function getLastPopulatedColumn(row) { - let col = row.length; - while(--col > 0) { - if(row[col].char || row[col].sgr) { - break; - } - } - return col; - } - - parser.on('complete', () => { - let output = ''; - let lastSgr = ''; - let line; - - canvas.slice(0, lastRow + 1).forEach(row => { - const lastCol = getLastPopulatedColumn(row) + 1; - - let i; - line = ''; - for(i = 0; i < lastCol; ++i) { - const col = row[i]; - if(col.sgr) { - lastSgr = col.sgr; - } - line += `${col.sgr || ''}${col.char || ' '}`; - } - - output += line; - - if(i < row.length) { - output += `${ANSI.blackBG()}${row.slice(i).map( () => ' ').join('')}${lastSgr}`; - } - - //if(options.startCol + options.cols < options.termWidth || options.forceLineTerm) { - if(options.startCol + i < options.termWidth || options.forceLineTerm) { - output += '\r\n'; - } - }); - - if(options.exportMode) { - // - // If we're in export mode, we do some additional hackery: - // - // * Hard wrap ALL lines at <= 79 *characters* (not visible columns) - // if a line must wrap early, we'll place a ESC[A ESC[C where - // represents chars to get back to the position we were previously at - // - // * Replace contig spaces with ESC[C as well to save... space. - // - // :TODO: this would be better to do as part of the processing above, but this will do for now - const MAX_CHARS = 79 - 8; // 79 max, - 8 for max ESC seq's we may prefix a line with - let exportOutput = ''; - - let m; - let afterSeq; - let wantMore; - let renderStart; - - splitTextAtTerms(output).forEach(fullLine => { - renderStart = 0; - - while(fullLine.length > 0) { - let splitAt; - const ANSI_REGEXP = ANSI.getFullMatchRegExp(); - wantMore = true; - - while((m = ANSI_REGEXP.exec(fullLine))) { - afterSeq = m.index + m[0].length; - - if(afterSeq < MAX_CHARS) { - // after current seq - splitAt = afterSeq; - } else { - if(m.index < MAX_CHARS) { - // before last found seq - splitAt = m.index; - wantMore = false; // can't eat up any more - } - - break; // seq's beyond this point are >= MAX_CHARS - } - } - - if(splitAt) { - if(wantMore) { - splitAt = Math.min(fullLine.length, MAX_CHARS - 1); - } - } else { - splitAt = Math.min(fullLine.length, MAX_CHARS - 1); - } - - const part = fullLine.slice(0, splitAt); - fullLine = fullLine.slice(splitAt); - renderStart += renderStringLength(part); - exportOutput += `${part}\r\n`; - - if(fullLine.length > 0) { // more to go for this line? - exportOutput += `${ANSI.up()}${ANSI.right(renderStart)}`; - } else { - exportOutput += ANSI.up(); - } - } - }); - - return cb(null, exportOutput); - } - - return cb(null, output); - }); - - parser.parse(input); -} - function isAnsiLine(line) { return isAnsi(line);// || renderStringLength(line) < line.length; } @@ -622,22 +428,23 @@ function isFormattedLine(line) { return false; } +// :TODO: rename to containsAnsi() function isAnsi(input) { if(!input || 0 === input.length) { return false; } - + // // * ANSI found - limited, just colors // * Full ANSI art - // * - // + // * + // // FULL ANSI art: // * SAUCE present & reports as ANSI art // * ANSI clear screen within first 2-3 codes // * ANSI movement codes (goto, right, left, etc.) - // - // * + // + // * /* readSAUCE(input, (err, sauce) => { if(!err && ('ANSi' === sauce.fileType || 'ANSiMation' === sauce.fileType)) { @@ -647,8 +454,8 @@ function isAnsi(input) { */ // :TODO: if a similar method is kept, use exec() until threshold - const ANSI_DET_REGEXP = /(?:\x1b\x5b)[\?=;0-9]*?[ABCDEFGHJKLMSTfhlmnprsu]/g; // eslint-disable-line no-control-regex - const m = input.match(ANSI_DET_REGEXP) || []; + const ANSI_DET_REGEXP = /(?:\x1b\x5b)[?=;0-9]*?[ABCDEFGHJKLMSTfhlmnprsu]/g; // eslint-disable-line no-control-regex + const m = input.match(ANSI_DET_REGEXP) || []; return m.length >= 4; // :TODO: do this reasonably, e.g. a percent or soemthing } diff --git a/core/system_menu_method.js b/core/system_menu_method.js index f968a493..8a20af02 100644 --- a/core/system_menu_method.js +++ b/core/system_menu_method.js @@ -33,7 +33,7 @@ function login(callingMenu, formData, extraArgs, cb) { return callingMenu.prevMenu(cb); } } - + // success! return callingMenu.nextMenu(cb); }); @@ -72,7 +72,7 @@ function prevMenu(callingMenu, formData, extraArgs, cb) { callingMenu.prevMenu( err => { if(err) { - callingMenu.client.log.error( { error : err.message }, 'Error attempting to fallback!'); + callingMenu.client.log.error( { error : err.message }, 'Error attempting to fallback!'); } return cb(err); }); @@ -119,7 +119,7 @@ function nextConf(callingMenu, formData, extraArgs, cb) { if(err) { return cb(err); // logged within changeMessageConference() } - + return reloadMenu(callingMenu, cb); }); } @@ -132,7 +132,7 @@ function prevArea(callingMenu, formData, extraArgs, cb) { if(err) { return cb(err); // logged within changeMessageArea() } - + return reloadMenu(callingMenu, cb); }); } @@ -155,10 +155,10 @@ function nextArea(callingMenu, formData, extraArgs, cb) { } function sendForgotPasswordEmail(callingMenu, formData, extraArgs, cb) { - const username = formData.value.username || callingMenu.client.user.username; + const username = formData.value.username || callingMenu.client.user.username; const WebPasswordReset = require('./web_password_reset.js').WebPasswordReset; - + WebPasswordReset.sendForgotPasswordEmail(username, err => { if(err) { callingMenu.client.log.warn( { err : err.message }, 'Failed sending forgot password email'); @@ -166,8 +166,8 @@ function sendForgotPasswordEmail(callingMenu, formData, extraArgs, cb) { if(extraArgs.next) { return callingMenu.gotoMenu(extraArgs.next, cb); - } - - return logoff(callingMenu, formData, extraArgs, cb); + } + + return logoff(callingMenu, formData, extraArgs, cb); }); } diff --git a/core/system_view_validate.js b/core/system_view_validate.js index e2a5b2e0..beb6bcce 100644 --- a/core/system_view_validate.js +++ b/core/system_view_validate.js @@ -99,7 +99,7 @@ function validateGeneralMailAddressedTo(data, cb) { function validateEmailAvail(data, cb) { // // This particular method allows empty data - e.g. no email entered - // + // if(!data || 0 === data.length) { return cb(null); } @@ -110,7 +110,7 @@ function validateEmailAvail(data, cb) { // // See http://stackoverflow.com/questions/7786058/find-the-regex-used-by-html5-forms-for-validation // - const emailRegExp = /[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9-]+(.[a-z0-9-]+)*/; + const emailRegExp = /[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(.[a-z0-9-]+)*/; if(!emailRegExp.test(data)) { return cb(new Error('Invalid email address')); } @@ -121,8 +121,8 @@ function validateEmailAvail(data, cb) { } else if(uids.length > 0) { return cb(new Error('Email address not unique')); } - - return cb(null); + + return cb(null); }); } diff --git a/core/telnet_bridge.js b/core/telnet_bridge.js index fa1754a5..30db1207 100644 --- a/core/telnet_bridge.js +++ b/core/telnet_bridge.js @@ -42,7 +42,7 @@ class TelnetClientConnection extends EventEmitter { this.client = client; } - + restorePipe() { if(!this.pipeRestored) { this.pipeRestored = true; @@ -68,14 +68,14 @@ class TelnetClientConnection extends EventEmitter { this.bridgeConnection.on('data', data => { this.client.term.rawWrite(data); - // + // // Wait for a terminal type request, and send it eactly once. // This is enough (in additional to other negotiations handled in telnet.js) // to get us in on most systems // if(!this.termSent && data.indexOf(IAC_DO_TERM_TYPE) > -1) { this.termSent = true; - this.bridgeConnection.write(this.getTermTypeNegotiationBuffer()); + this.bridgeConnection.write(this.getTermTypeNegotiationBuffer()); } }); @@ -102,9 +102,9 @@ class TelnetClientConnection extends EventEmitter { // actual/current terminal type. // let bufs = buffers(); - + bufs.push(new Buffer( - [ + [ 255, // IAC 250, // SB 24, // TERMINAL-TYPE @@ -113,9 +113,9 @@ class TelnetClientConnection extends EventEmitter { )); bufs.push( - new Buffer(this.client.term.termType), // e.g. "ansi" + new Buffer(this.client.term.termType), // e.g. "ansi" new Buffer( [ 255, 240 ] ) // IAC, SE - ); + ); return bufs.toBuffer(); } @@ -128,9 +128,9 @@ exports.getModule = class TelnetBridgeModule extends MenuModule { this.config = options.menuConfig.config; // defaults - this.config.port = this.config.port || 23; + this.config.port = this.config.port || 23; } - + initSequence() { let clientTerminated; const self = this; @@ -158,7 +158,7 @@ exports.getModule = class TelnetBridgeModule extends MenuModule { self.client.term.write(` Connecting to ${connectOpts.host}, please wait...\n`); const telnetConnection = new TelnetClientConnection(self.client); - + telnetConnection.on('connected', () => { self.client.log.info(connectOpts, 'Telnet bridge connection established'); diff --git a/core/text_view.js b/core/text_view.js index f1b3ee7e..8bd38213 100644 --- a/core/text_view.js +++ b/core/text_view.js @@ -35,7 +35,7 @@ function TextView(options) { this.justify = options.justify || 'right'; this.resizable = miscUtil.valueWithDefault(options.resizable, true); this.horizScroll = miscUtil.valueWithDefault(options.horizScroll, true); - + if(_.isString(options.textOverflow)) { this.textOverflow = options.textOverflow; } @@ -44,19 +44,19 @@ function TextView(options) { this.textMaskChar = options.textMaskChar; } -/* + /* this.drawText = function(s) { - // + // // |<- this.maxLength // ABCDEFGHIJK // |ABCDEFG| ^_ this.text.length // ^-- this.dimens.width // - let textToDraw = _.isString(this.textMaskChar) ? - new Array(s.length + 1).join(this.textMaskChar) : + let textToDraw = _.isString(this.textMaskChar) ? + new Array(s.length + 1).join(this.textMaskChar) : stylizeString(s, this.hasFocus ? this.focusTextStyle : this.textStyle); - + if(textToDraw.length > this.dimens.width) { if(this.hasFocus) { if(this.horizScroll) { @@ -64,7 +64,7 @@ function TextView(options) { } } else { if(textToDraw.length > this.dimens.width) { - if(this.textOverflow && + if(this.textOverflow && this.dimens.width > this.textOverflow.length && textToDraw.length - this.textOverflow.length >= this.textOverflow.length) { @@ -72,7 +72,7 @@ function TextView(options) { } else { textToDraw = textToDraw.substr(0, this.dimens.width); } - } + } } } @@ -89,7 +89,7 @@ function TextView(options) { this.drawText = function(s) { - // + // // |<- this.maxLength // ABCDEFGHIJK // |ABCDEFG| ^_ this.text.length @@ -97,26 +97,26 @@ function TextView(options) { // let renderLength = renderStringLength(s); // initial; may be adjusted below: - let textToDraw = _.isString(this.textMaskChar) ? - new Array(renderLength + 1).join(this.textMaskChar) : + let textToDraw = _.isString(this.textMaskChar) ? + new Array(renderLength + 1).join(this.textMaskChar) : stylizeString(s, this.hasFocus ? this.focusTextStyle : this.textStyle); - + renderLength = renderStringLength(textToDraw); - + if(renderLength >= this.dimens.width) { if(this.hasFocus) { if(this.horizScroll) { textToDraw = renderSubstr(textToDraw, renderLength - this.dimens.width, renderLength); } } else { - if(this.textOverflow && + if(this.textOverflow && this.dimens.width > this.textOverflow.length && renderLength - this.textOverflow.length >= this.textOverflow.length) { - textToDraw = renderSubstr(textToDraw, 0, this.dimens.width - this.textOverflow.length) + this.textOverflow; + textToDraw = renderSubstr(textToDraw, 0, this.dimens.width - this.textOverflow.length) + this.textOverflow; } else { textToDraw = renderSubstr(textToDraw, 0, this.dimens.width); - } + } } } @@ -128,7 +128,7 @@ function TextView(options) { this.justify, this.hasFocus ? this.getFocusSGR() : this.getSGR(), this.getStyleSGR(1) || this.getSGR() - ), + ), false // no converting CRLF needed ); }; @@ -136,7 +136,7 @@ function TextView(options) { this.getEndOfTextColumn = function() { var offset = Math.min(this.text.length, this.dimens.width); - return this.position.col + offset; + return this.position.col + offset; }; this.setText(options.text || '', false); // false=do not redraw now @@ -168,7 +168,7 @@ TextView.prototype.setFocus = function(focused) { TextView.super_.prototype.setFocus.call(this, focused); this.redraw(); - + this.client.term.write(ansi.goto(this.position.row, this.getEndOfTextColumn())); this.client.term.write(this.getFocusSGR()); }; @@ -184,7 +184,7 @@ TextView.prototype.setText = function(text, redraw) { text = text.toString(); } - text = pipeToAnsi(stripAllLineFeeds(text), this.client); // expand MCI/etc. + text = pipeToAnsi(stripAllLineFeeds(text), this.client); // expand MCI/etc. var widthDelta = 0; if(this.text && this.text !== text) { @@ -199,7 +199,7 @@ TextView.prototype.setText = function(text, redraw) { } // :TODO: it would be nice to be able to stylize strings with MCI and {special} MCI syntax, e.g. "|BN {UN!toUpper}" - this.text = stylizeString(this.text, this.hasFocus ? this.focusTextStyle : this.textStyle); + this.text = stylizeString(this.text, this.hasFocus ? this.focusTextStyle : this.textStyle); if(this.autoScale.width) { this.dimens.width = renderStringLength(this.text) + widthDelta; @@ -214,7 +214,7 @@ TextView.prototype.setText = function(text, redraw) { TextView.prototype.setText = function(text) { if(!_.isString(text)) { text = text.toString(); - } + } var widthDelta = 0; if(this.text && this.text !== text) { @@ -227,7 +227,7 @@ TextView.prototype.setText = function(text) { this.text = this.text.substr(0, this.maxLength); } - this.text = stylizeString(this.text, this.hasFocus ? this.focusTextStyle : this.textStyle); + this.text = stylizeString(this.text, this.hasFocus ? this.focusTextStyle : this.textStyle); //if(this.resizable) { // this.dimens.width = this.text.length + widthDelta; @@ -254,9 +254,9 @@ TextView.prototype.setPropertyValue = function(propName, value) { if(true === value) { this.textMaskChar = this.client.currentTheme.helpers.getPasswordChar(); } - break; + break; } - + TextView.super_.prototype.setPropertyValue.call(this, propName, value); }; diff --git a/core/theme.js b/core/theme.js index 0796b8ab..a1045a18 100644 --- a/core/theme.js +++ b/core/theme.js @@ -87,8 +87,8 @@ function loadTheme(themeID, cb) { if(err) { return cb(err); } - - if(!_.isObject(theme.info) || + + if(!_.isObject(theme.info) || !_.isString(theme.info.name) || !_.isString(theme.info.author)) { @@ -114,16 +114,16 @@ const IMMUTABLE_MCI_PROPERTIES = [ function getMergedTheme(menuConfig, promptConfig, theme) { assert(_.isObject(menuConfig)); assert(_.isObject(theme)); - - // :TODO: merge in defaults (customization.defaults{} ) - // :TODO: apply generic stuff, e.g. "VM" (vs "VM1") - - // - // Create a *clone* of menuConfig (menu.hjson) then bring in - // promptConfig (prompt.hjson) - // + + // :TODO: merge in defaults (customization.defaults{} ) + // :TODO: apply generic stuff, e.g. "VM" (vs "VM1") + + // + // Create a *clone* of menuConfig (menu.hjson) then bring in + // promptConfig (prompt.hjson) + // var mergedTheme = _.cloneDeep(menuConfig); - + if(_.isObject(promptConfig.prompts)) { mergedTheme.prompts = _.cloneDeep(promptConfig.prompts); } @@ -136,8 +136,8 @@ function getMergedTheme(menuConfig, promptConfig, theme) { // // merge customizer to disallow immutable MCI properties - // - var mciCustomizer = function(objVal, srcVal, key) { + // + var mciCustomizer = function(objVal, srcVal, key) { return IMMUTABLE_MCI_PROPERTIES.indexOf(key) > -1 ? objVal : srcVal; }; @@ -159,69 +159,69 @@ function getMergedTheme(menuConfig, promptConfig, theme) { } else { if(_.has(src, [ formKey, 'mci' ])) { mergeMciProperties(dest, src[formKey].mci); - } + } } } - - // - // menu.hjson can have a couple different structures: - // 1) Explicit declaration of expected MCI code(s) under 'form:' before a 'mci' block - // (this allows multiple layout types defined by one menu for example) - // - // 2) Non-explicit declaration: 'mci' directly under 'form:' - // - // theme.hjson has it's own mix: - // 1) Explicit: Form ID before 'mci' (generally used where there are > 1 forms) - // - // 2) Non-explicit: 'mci' directly under an entry - // - // Additionally, #1 or #2 may be under an explicit key of MCI code(s) to match up - // with menu.hjson in #1. - // - // * When theming an explicit menu.hjson entry (1), we will use a matching explicit - // entry with a matching MCI code(s) key in theme.hjson (e.g. menu="ETVM"/theme="ETVM" - // and fall back to generic if a match is not found. - // - // * If theme.hjson provides form ID's, use them. Otherwise, we'll apply directly assuming - // there is a generic 'mci' block. - // - function applyToForm(form, menuTheme, formKey) { + + // + // menu.hjson can have a couple different structures: + // 1) Explicit declaration of expected MCI code(s) under 'form:' before a 'mci' block + // (this allows multiple layout types defined by one menu for example) + // + // 2) Non-explicit declaration: 'mci' directly under 'form:' + // + // theme.hjson has it's own mix: + // 1) Explicit: Form ID before 'mci' (generally used where there are > 1 forms) + // + // 2) Non-explicit: 'mci' directly under an entry + // + // Additionally, #1 or #2 may be under an explicit key of MCI code(s) to match up + // with menu.hjson in #1. + // + // * When theming an explicit menu.hjson entry (1), we will use a matching explicit + // entry with a matching MCI code(s) key in theme.hjson (e.g. menu="ETVM"/theme="ETVM" + // and fall back to generic if a match is not found. + // + // * If theme.hjson provides form ID's, use them. Otherwise, we'll apply directly assuming + // there is a generic 'mci' block. + // + function applyToForm(form, menuTheme, formKey) { if(_.isObject(form.mci)) { // non-explicit: no MCI code(s) key assumed since we found 'mci' directly under form ID applyThemeMciBlock(form.mci, menuTheme, formKey); - + } else { var menuMciCodeKeys = _.remove(_.keys(form), function pred(k) { - return k === k.toUpperCase(); // remove anything not uppercase + return k === k.toUpperCase(); // remove anything not uppercase }); - + menuMciCodeKeys.forEach(function mciKeyEntry(mciKey) { - var applyFrom; + var applyFrom; if(_.has(menuTheme, [ mciKey, 'mci' ])) { applyFrom = menuTheme[mciKey]; } else { applyFrom = menuTheme; } - + applyThemeMciBlock(form[mciKey].mci, applyFrom); }); } } - + [ 'menus', 'prompts' ].forEach(function areaEntry(sectionName) { _.keys(mergedTheme[sectionName]).forEach(function menuEntry(menuName) { var createdFormSection = false; var mergedThemeMenu = mergedTheme[sectionName][menuName]; - + if(_.has(theme, [ 'customization', sectionName, menuName ])) { var menuTheme = theme.customization[sectionName][menuName]; - + // config block is direct assign/overwrite // :TODO: should probably be _.merge() if(menuTheme.config) { mergedThemeMenu.config = _.assign(mergedThemeMenu.config || {}, menuTheme.config); } - + if('menus' === sectionName) { if(_.isObject(mergedThemeMenu.form)) { getFormKeys(mergedThemeMenu.form).forEach(function formKeyEntry(formKey) { @@ -232,7 +232,7 @@ function getMergedTheme(menuConfig, promptConfig, theme) { // // Not specified at menu level means we apply anything from the // theme to form.0.mci{} - // + // mergedThemeMenu.form = { 0 : { mci : { } } }; mergeMciProperties(mergedThemeMenu.form[0], menuTheme); createdFormSection = true; @@ -241,9 +241,9 @@ function getMergedTheme(menuConfig, promptConfig, theme) { } else if('prompts' === sectionName) { // no 'form' or form keys for prompts -- direct to mci applyToForm(mergedThemeMenu, menuTheme); - } + } } - + // // Finished merging for this menu/prompt // @@ -259,13 +259,13 @@ function getMergedTheme(menuConfig, promptConfig, theme) { } }); }); - + return mergedTheme; } function initAvailableThemes(cb) { - + async.waterfall( [ function loadMenuConfig(callback) { @@ -285,9 +285,9 @@ function initAvailableThemes(cb) { } return callback( - null, - menuConfig, - promptConfig, + null, + menuConfig, + promptConfig, files.filter( f => { // sync normally not allowed -- initAvailableThemes() is a startup-only method, however return fs.statSync(paths.join(Config.paths.themes, f)).isDirectory(); @@ -363,7 +363,7 @@ function setClientTheme(client, themeId) { logMsg = 'Failed setting theme by system default ID; Using the first one we can find'; } } - + client.log.debug( { themeId : themeId, info : client.currentTheme.info }, logMsg); } @@ -371,7 +371,7 @@ function getThemeArt(options, cb) { // // options - required: // name - // + // // options - optional // client - needed for user's theme/etc. // themeId @@ -388,7 +388,7 @@ function getThemeArt(options, cb) { // :TODO: replace asAnsi stuff with something like retrieveAs = 'ansi' | 'pipe' | ... // :TODO: Some of these options should only be set if not provided! options.asAnsi = true; // always convert to ANSI - options.readSauce = true; // read SAUCE, if avail + options.readSauce = true; // read SAUCE, if avail options.random = _.get(options, 'random', true); // FILENAME.EXT support // @@ -406,7 +406,7 @@ function getThemeArt(options, cb) { // if('/' === options.name.charAt(0)) { // just take the path as-is - options.basePath = paths.dirname(options.name); + options.basePath = paths.dirname(options.name); } else if(options.name.indexOf('/') > -1) { // make relative to base BBS dir options.basePath = paths.join(__dirname, '../', paths.dirname(options.name)); @@ -432,7 +432,7 @@ function getThemeArt(options, cb) { if(artInfo || Config.defaults.theme === options.themeId) { return callback(null, artInfo); } - + options.basePath = paths.join(Config.paths.themes, Config.defaults.theme); art.getArt(options.name, options, (err, artInfo) => { return callback(null, artInfo); @@ -442,11 +442,11 @@ function getThemeArt(options, cb) { if(artInfo) { return callback(null, artInfo); } - + options.basePath = Config.paths.art; art.getArt(options.name, options, (err, artInfo) => { return callback(err, artInfo); - }); + }); } ], function complete(err, artInfo) { @@ -483,7 +483,7 @@ function displayThemeArt(options, cb) { /* function displayThemedPrompt(name, client, options, cb) { - + async.waterfall( [ function loadConfig(callback) { @@ -511,14 +511,14 @@ function displayThemedPrompt(name, client, options, cb) { // // If we did not clear the screen, don't let the font change - // + // const dispOptions = Object.assign( {}, promptConfig.options ); if(!options.clearScreen) { dispOptions.font = 'not_really_a_font!'; } displayThemedAsset( - promptConfig.art, + promptConfig.art, client, dispOptions, (err, artData) => { @@ -576,7 +576,7 @@ function displayThemedPrompt(name, client, options, cb) { } displayThemedAsset( - promptConfig.art, + promptConfig.art, client, dispOptions, (err, artInfo) => { @@ -593,7 +593,7 @@ function displayThemedPrompt(name, client, options, cb) { // no need to query cursor - we're not gonna use it return callback(null, promptConfig, artInfo); } - + client.once('cursor position report', pos => { artInfo.startRow = pos[0] - artInfo.height; return callback(null, promptConfig, artInfo); @@ -627,7 +627,7 @@ function displayThemedPrompt(name, client, options, cb) { if(options.clearPrompt) { if(artInfo.startRow && artInfo.height) { client.term.rawWrite(ansi.goto(artInfo.startRow, 1)); - + // Note: Does not work properly in NetRunner < 2.0b17: client.term.rawWrite(ansi.deleteLine(artInfo.height)); } else { @@ -654,7 +654,7 @@ function displayThemedPrompt(name, client, options, cb) { // // Pause prompts are a special prompt by the name 'pause'. -// +// function displayThemedPause(client, options, cb) { if(!cb && _.isFunction(options)) { @@ -699,7 +699,7 @@ function displayThemedAsset(assetSpec, client, options, cb) { }); break; - case 'method' : + case 'method' : // :TODO: fetch & render via method break; diff --git a/core/tic_file_info.js b/core/tic_file_info.js index d2216d66..27e31e4c 100644 --- a/core/tic_file_info.js +++ b/core/tic_file_info.js @@ -28,7 +28,7 @@ module.exports = class TicFileInfo { static get requiredFields() { return [ - 'Area', 'Origin', 'From', 'File', 'Crc', + 'Area', 'Origin', 'From', 'File', 'Crc', // :TODO: validate this: //'Path', 'Seenby' // these two are questionable; some systems don't send them? ]; @@ -43,16 +43,16 @@ module.exports = class TicFileInfo { if(value) { // // We call toString() on values to ensure numbers, addresses, etc. are converted - // + // joinWith = joinWith || ''; if(Array.isArray(value)) { return value.map(v => v.toString() ).join(joinWith); } - + return value.toString(); } } - + get filePath() { return paths.join(paths.dirname(this.path), this.getAsString('File')); } @@ -86,7 +86,7 @@ module.exports = class TicFileInfo { const localInfo = { areaTag : config.localAreaTags.find( areaTag => areaTag.toUpperCase() === area ), }; - + if(!localInfo.areaTag) { return callback(Errors.Invalid(`No local area for "Area" of ${area}`)); } @@ -112,7 +112,7 @@ module.exports = class TicFileInfo { return callback(null, localInfo); }, function checksumAndSize(localInfo, callback) { - const crcTic = self.get('Crc'); + const crcTic = self.get('Crc'); const stream = fs.createReadStream(self.filePath); const crc = new CRC32(); let sizeActual = 0; @@ -193,7 +193,7 @@ module.exports = class TicFileInfo { // This is an optional keyword." // const to = this.get('To'); - + if(!to) { return allowNonExplicit; } @@ -219,10 +219,10 @@ module.exports = class TicFileInfo { let key; let value; let entry; - + lines.forEach(line => { keyEnd = line.search(/\s/); - + if(keyEnd < 0) { keyEnd = line.length; } @@ -253,7 +253,7 @@ module.exports = class TicFileInfo { value = parseInt(value, 16); break; - case 'size' : + case 'size' : value = parseInt(value, 10); break; diff --git a/core/ticker_text_view.js b/core/ticker_text_view.js deleted file mode 100644 index 6574880b..00000000 --- a/core/ticker_text_view.js +++ /dev/null @@ -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); - } -}; \ No newline at end of file diff --git a/core/toggle_menu_view.js b/core/toggle_menu_view.js index 35676193..27ae2169 100644 --- a/core/toggle_menu_view.js +++ b/core/toggle_menu_view.js @@ -1,13 +1,11 @@ /* jslint node: true */ 'use strict'; -var MenuView = require('./menu_view.js').MenuView; -var ansi = require('./ansi_term.js'); -var strUtil = require('./string_util.js'); +const MenuView = require('./menu_view.js').MenuView; +const strUtil = require('./string_util.js'); -var util = require('util'); -var assert = require('assert'); -var _ = require('lodash'); +const util = require('util'); +const assert = require('assert'); exports.ToggleMenuView = ToggleMenuView; @@ -44,7 +42,7 @@ ToggleMenuView.prototype.redraw = function() { var item = this.items[i]; var text = strUtil.stylizeString( item.text, i === this.focusedItemIndex && this.hasFocus ? this.focusTextStyle : this.textStyle); - + if(1 === i) { //console.log(this.styleColor1) //var sepColor = this.getANSIColor(this.styleColor1 || this.getColor()); diff --git a/core/upload.js b/core/upload.js index 5a49a0ca..b4130433 100644 --- a/core/upload.js +++ b/core/upload.js @@ -85,7 +85,7 @@ exports.getModule = class UploadModule extends MenuModule { fileDetailsContinue : (formData, extraArgs, cb) => { // see displayFileDetailsPageForUploadEntry() for this hackery: - cb(null); + cb(null); return this.fileDetailsCurrentEntrySubmitCallback(null, formData.value); // move on to the next entry, if any }, @@ -119,7 +119,7 @@ exports.getModule = class UploadModule extends MenuModule { return cb(null); } - }; + }; } getSaveState() { @@ -143,12 +143,12 @@ exports.getModule = class UploadModule extends MenuModule { isBlindUpload() { return 'blind' === this.uploadType; } isFileTransferComplete() { return !_.isUndefined(this.recvFilePaths); } - + initSequence() { const self = this; if(0 === this.availAreas.length) { - // + // return this.gotoMenu(this.menuConfig.config.noUploadAreasAvailMenu || 'fileBaseNoUploadAreasAvail'); } @@ -185,7 +185,7 @@ exports.getModule = class UploadModule extends MenuModule { // need a terminator for various external protocols this.tempRecvDirectory = pathWithTerminatingSeparator(tempRecvDirectory); - + const modOpts = { extraArgs : { recvDirectory : this.tempRecvDirectory, // we'll move files from here to their area container once processed/confirmed @@ -203,8 +203,8 @@ exports.getModule = class UploadModule extends MenuModule { // Upon completion, we'll re-enter the module with some file paths handed to us // return this.gotoMenu( - this.menuConfig.config.fileTransferProtocolSelection || 'fileTransferProtocolSelection', - modOpts, + this.menuConfig.config.fileTransferProtocolSelection || 'fileTransferProtocolSelection', + modOpts, cb ); }); @@ -219,7 +219,7 @@ exports.getModule = class UploadModule extends MenuModule { const fmtObj = Object.assign( {}, stepInfo); let stepIndicatorFmt = ''; - let logStepFmt; + let logStepFmt; const fmtConfig = this.menuConfig.config; @@ -228,7 +228,7 @@ exports.getModule = class UploadModule extends MenuModule { const indicator = { }; const self = this; - + function updateIndicator(mci, isFinished) { indicator.mci = mci; @@ -253,7 +253,7 @@ exports.getModule = class UploadModule extends MenuModule { updateIndicator(MciViewIds.processing.calcHashIndicator); break; - case 'hash_finish' : + case 'hash_finish' : stepIndicatorFmt = fmtConfig.calcHashCompleteFormat || 'Finished calculating hash/checksums'; updateIndicator(MciViewIds.processing.calcHashIndicator, true); break; @@ -263,7 +263,7 @@ exports.getModule = class UploadModule extends MenuModule { updateIndicator(MciViewIds.processing.archiveListIndicator); break; - case 'archive_list_finish' : + case 'archive_list_finish' : fmtObj.archivedFileCount = stepInfo.archiveEntries.length; stepIndicatorFmt = fmtConfig.extractArchiveListFinishFormat || 'Archive list extracted ({archivedFileCount} files)'; updateIndicator(MciViewIds.processing.archiveListIndicator, true); @@ -273,7 +273,7 @@ exports.getModule = class UploadModule extends MenuModule { stepIndicatorFmt = fmtConfig.extractArchiveListFailedFormat || 'Archive list extraction failed'; break; - case 'desc_files_start' : + case 'desc_files_start' : stepIndicatorFmt = fmtConfig.processingDescFilesFormat || 'Processing description files'; updateIndicator(MciViewIds.processing.descFileIndicator); break; @@ -289,7 +289,7 @@ exports.getModule = class UploadModule extends MenuModule { } fmtObj.stepIndicatorText = stringFormat(stepIndicatorFmt, fmtObj); - + if(this.hasProcessingArt) { this.updateCustomViewTextsWithFilter('processing', MciViewIds.processing.customRangeStart, fmtObj, { appendMultiLine : true } ); @@ -339,7 +339,7 @@ exports.getModule = class UploadModule extends MenuModule { return nextScanStep(null); } - self.client.log.debug('Scanning file', { filePath : filePath } ); + self.client.log.debug('Scanning file', { filePath : filePath } ); scanFile(filePath, scanOpts, handleScanStep, (err, fileEntry, dupeEntries) => { if(err) { @@ -389,7 +389,7 @@ exports.getModule = class UploadModule extends MenuModule { // name changed; ajust before persist newEntry.fileName = paths.basename(finalPath); } - + return nextEntry(null); // still try next file } @@ -474,7 +474,7 @@ exports.getModule = class UploadModule extends MenuModule { if(err) { return nextDupe(err); } - + const areaInfo = getFileAreaByTag(dupe.areaTag); if(areaInfo) { dupe.areaName = areaInfo.name; @@ -553,12 +553,12 @@ exports.getModule = class UploadModule extends MenuModule { return callback(null, scanResults); } - return self.displayDupesPage(scanResults.dupes, () => { + return self.displayDupesPage(scanResults.dupes, () => { return callback(null, scanResults); }); }, function prepDetails(scanResults, callback) { - return self.prepDetailsForUpload(scanResults, callback); + return self.prepDetailsForUpload(scanResults, callback); }, function startMovingAndPersistingToDatabase(scanResults, callback) { // @@ -583,14 +583,14 @@ exports.getModule = class UploadModule extends MenuModule { displayOptionsPage(cb) { const self = this; - + async.series( [ function prepArtAndViewController(callback) { return self.prepViewControllerWithArt( - 'options', - FormIds.options, - { clearScreen : true, trailingLF : false }, + 'options', + FormIds.options, + { clearScreen : true, trailingLF : false }, callback ); }, @@ -621,7 +621,7 @@ exports.getModule = class UploadModule extends MenuModule { fileNameView.setText(sanatizeFilename(fileNameView.getData())); } }); - + self.uploadType = 'blind'; uploadTypeView.setFocusItemIndex(0); // default to blind fileNameView.setText(blindFileNameText); @@ -658,14 +658,14 @@ exports.getModule = class UploadModule extends MenuModule { displayFileDetailsPageForUploadEntry(fileEntry, cb) { const self = this; - + async.waterfall( [ function prepArtAndViewController(callback) { return self.prepViewControllerWithArt( - 'fileDetails', + 'fileDetails', FormIds.fileDetails, - { clearScreen : true, trailingLF : false }, + { clearScreen : true, trailingLF : false }, err => { return callback(err); } diff --git a/core/user.js b/core/user.js index 09d26163..76c493ea 100644 --- a/core/user.js +++ b/core/user.js @@ -49,7 +49,7 @@ module.exports = class User { active : 2, }; } - + isAuthenticated() { return true === this.authenticated; } @@ -83,7 +83,7 @@ module.exports = class User { groupNames = [ groupNames ]; } - const isMember = groupNames.some(gn => (-1 !== this.groups.indexOf(gn))); + const isMember = groupNames.some(gn => (-1 !== this.groups.indexOf(gn))); return isMember; } @@ -91,11 +91,11 @@ module.exports = class User { if(this.isRoot() || this.isGroupMember('sysops')) { return 100; } - + if(this.isGroupMember('users')) { return 30; } - + return 10; // :TODO: Is this what we want? } @@ -203,14 +203,14 @@ module.exports = class User { if(err) { return callback(err); } - + self.userId = this.lastID; // Do not require activation for userId 1 (root/admin) if(User.RootUserID === self.userId) { self.properties.account_status = User.AccountStatus.active; } - + return callback(null, trans); } ); @@ -220,7 +220,7 @@ module.exports = class User { if(err) { return callback(err); } - + self.properties.pw_pbkdf2_salt = info.salt; self.properties.pw_pbkdf2_dk = info.dk; return callback(null, trans); @@ -283,8 +283,8 @@ module.exports = class User { userDb.run( `REPLACE INTO user_property (user_id, prop_name, prop_value) - VALUES (?, ?, ?);`, - [ this.userId, propName, propValue ], + VALUES (?, ?, ?);`, + [ this.userId, propName, propValue ], err => { if(cb) { return cb(err); @@ -334,7 +334,7 @@ module.exports = class User { if(err) { return cb(err); } - + stmt.finalize( () => { return cb(null); }); @@ -346,7 +346,7 @@ module.exports = class User { if(err) { return cb(err); } - + const newProperties = { pw_pbkdf2_salt : info.salt, pw_pbkdf2_dk : info.dk, @@ -395,7 +395,7 @@ module.exports = class User { } ); } - + static isRootUserId(userId) { return (User.RootUserID === userId); } @@ -466,11 +466,11 @@ module.exports = class User { if(err) { return cb(err); } - + if(row) { return cb(null, row.user_name); } - + return cb(Errors.DoesNotExist('No matching user ID')); } ); @@ -498,7 +498,7 @@ module.exports = class User { if(err) { return cb(err); } - properties[row.prop_name] = row.prop_value; + properties[row.prop_name] = row.prop_value; }, (err) => { return cb(err, err ? null : properties); }); @@ -512,12 +512,12 @@ module.exports = class User { `SELECT user_id FROM user_property WHERE prop_name = ? AND prop_value = ?;`, - [ propName, propValue ], + [ propName, propValue ], (err, row) => { if(row) { userIds.push(row.user_id); } - }, + }, () => { return cb(null, userIds); } @@ -557,7 +557,7 @@ module.exports = class User { return nextUser(err, user); } ); - }, + }, (err, transformed) => { return cb(err, transformed); }); @@ -594,14 +594,14 @@ module.exports = class User { }); } - static generatePasswordDerivedKey(password, salt, cb) { + static generatePasswordDerivedKey(password, salt, cb) { password = new Buffer(password).toString('hex'); crypto.pbkdf2(password, salt, User.PBKDF2.iterations, User.PBKDF2.keyLen, 'sha1', (err, dk) => { if(err) { return cb(err); } - + return cb(null, dk.toString('hex')); }); } diff --git a/core/user_config.js b/core/user_config.js index 432cdade..70e1f068 100644 --- a/core/user_config.js +++ b/core/user_config.js @@ -28,10 +28,10 @@ const MciCodeIds = { TermHeight : 8, Theme : 9, Password : 10, - PassConfirm : 11, + PassConfirm : 11, ThemeInfo : 20, ErrorMsg : 21, - + SaveCancel : 25, }; @@ -52,11 +52,11 @@ exports.getModule = class UserConfigModule extends MenuModule { if(self.client.user.properties.email_address.toLowerCase() === data.toLowerCase()) { return cb(null); } - + // Otherwise we can use the standard system method return sysValidate.validateEmailAvail(data, cb); }, - + validatePassword : function(data, cb) { // // Blank is OK - this means we won't be changing it @@ -64,23 +64,23 @@ exports.getModule = class UserConfigModule extends MenuModule { if(!data || 0 === data.length) { return cb(null); } - + // Otherwise we can use the standard system method return sysValidate.validatePasswordSpec(data, cb); }, - + validatePassConfirmMatch : function(data, cb) { var passwordView = self.getView(MciCodeIds.Password); cb(passwordView.getData() === data ? null : new Error('Passwords do not match')); }, - + viewValidationListener : function(err, cb) { var errMsgView = self.getView(MciCodeIds.ErrorMsg); var newFocusId; if(errMsgView) { if(err) { errMsgView.setText(err.message); - + if(err.view.getId() === MciCodeIds.PassConfirm) { newFocusId = MciCodeIds.Password; var passwordView = self.getView(MciCodeIds.Password); @@ -93,13 +93,13 @@ exports.getModule = class UserConfigModule extends MenuModule { } cb(newFocusId); }, - + // // Handlers // saveChanges : function(formData, extraArgs, cb) { assert(formData.value.password === formData.value.passwordConfirm); - + const newProperties = { real_name : formData.value.realName, birthdate : new Date(Date.parse(formData.value.birthdate)).toISOString(), @@ -108,15 +108,15 @@ exports.getModule = class UserConfigModule extends MenuModule { affiliation : formData.value.affils, email_address : formData.value.email, web_address : formData.value.web, - term_height : formData.value.termHeight.toString(), + term_height : formData.value.termHeight.toString(), theme_id : self.availThemeInfo[formData.value.theme].themeId, }; - + // runtime set theme theme.setClientTheme(self.client, newProperties.theme_id); - + // persist all changes - self.client.user.persistProperties(newProperties, err => { + self.client.user.persistProperties(newProperties, err => { if(err) { self.client.log.warn( { error : err.toString() }, 'Failed persisting updated properties'); // :TODO: warn end user! @@ -126,7 +126,7 @@ exports.getModule = class UserConfigModule extends MenuModule { // New password if it's not empty // self.client.log.info('User updated properties'); - + if(formData.value.password.length > 0) { self.client.user.setNewAuthCredentials(formData.value.password, err => { if(err) { @@ -155,7 +155,7 @@ exports.getModule = class UserConfigModule extends MenuModule { } const self = this; - const vc = self.viewControllers.menu = new ViewController( { client : self.client} ); + const vc = self.viewControllers.menu = new ViewController( { client : self.client} ); let currentThemeIdIndex = 0; async.series( @@ -164,7 +164,7 @@ exports.getModule = class UserConfigModule extends MenuModule { vc.loadFromMenuConfig( { callingMenu : self, mciMap : mciData.menu }, callback); }, function prepareAvailableThemes(callback) { - self.availThemeInfo = _.sortBy(_.map(theme.getAvailableThemes(), function makeThemeInfo(t, themeId) { + self.availThemeInfo = _.sortBy(_.map(theme.getAvailableThemes(), function makeThemeInfo(t, themeId) { return { themeId : themeId, name : t.info.name, @@ -173,11 +173,11 @@ exports.getModule = class UserConfigModule extends MenuModule { group : _.isString(t.info.group) ? t.info.group : '', }; }), 'name'); - + currentThemeIdIndex = _.findIndex(self.availThemeInfo, function cmp(ti) { return ti.themeId === self.client.user.properties.theme_id; }); - + callback(null); }, function populateViews(callback) { @@ -191,19 +191,19 @@ exports.getModule = class UserConfigModule extends MenuModule { self.setViewText('menu', MciCodeIds.Email, user.properties.email_address); self.setViewText('menu', MciCodeIds.Web, user.properties.web_address); self.setViewText('menu', MciCodeIds.TermHeight, user.properties.term_height.toString()); - - + + var themeView = self.getView(MciCodeIds.Theme); if(themeView) { themeView.setItems(_.map(self.availThemeInfo, 'name')); themeView.setFocusItemIndex(currentThemeIdIndex); } - + var realNameView = self.getView(MciCodeIds.RealName); if(realNameView) { realNameView.setFocus(true); // :TODO: HACK! menu.hjson sets focus, but manual population above breaks this. Needs a real fix! } - + callback(null); } ], diff --git a/core/user_group.js b/core/user_group.js index 3903f2c3..db444296 100644 --- a/core/user_group.js +++ b/core/user_group.js @@ -1,11 +1,10 @@ /* jslint node: true */ 'use strict'; -var userDb = require('./database.js').dbs.user; -var Config = require('./config.js').config; +const userDb = require('./database.js').dbs.user; -var async = require('async'); -var _ = require('lodash'); +const async = require('async'); +const _ = require('lodash'); exports.getGroupsForUser = getGroupsForUser; exports.addUserToGroup = addUserToGroup; @@ -13,23 +12,22 @@ exports.addUserToGroups = addUserToGroups; exports.removeUserFromGroup = removeUserFromGroup; function getGroupsForUser(userId, cb) { - var sql = - 'SELECT group_name ' + - 'FROM user_group_member ' + - 'WHERE user_id=?;'; + const sql = + `SELECT group_name + FROM user_group_member + WHERE user_id=?;`; - var groups = []; + const groups = []; - userDb.each(sql, [ userId ], function rowData(err, row) { + userDb.each(sql, [ userId ], (err, row) => { if(err) { - cb(err); - return; - } else { - groups.push(row.group_name); + return cb(err); } + + groups.push(row.group_name); }, - function complete() { - cb(null, groups); + () => { + return cb(null, groups); }); } @@ -40,31 +38,31 @@ function addUserToGroup(userId, groupName, transOrDb, cb) { } transOrDb.run( - 'REPLACE INTO user_group_member (group_name, user_id) ' + - 'VALUES(?, ?);', + `REPLACE INTO user_group_member (group_name, user_id) + VALUES(?, ?);`, [ groupName, userId ], - function complete(err) { - cb(err); + err => { + return cb(err); } ); } function addUserToGroups(userId, groups, transOrDb, cb) { - async.each(groups, function item(groupName, next) { - addUserToGroup(userId, groupName, transOrDb, next); - }, function complete(err) { - cb(err); + async.each(groups, (groupName, nextGroupName) => { + return addUserToGroup(userId, groupName, transOrDb, nextGroupName); + }, err => { + return cb(err); }); } function removeUserFromGroup(userId, groupName, cb) { userDb.run( - 'DELETE FROM user_group_member ' + - 'WHERE group_name=? AND user_id=?;', + `DELETE FROM user_group_member + WHERE group_name=? AND user_id=?;`, [ groupName, userId ], - function complete(err) { - cb(err); + err => { + return cb(err); } ); } diff --git a/core/user_list.js b/core/user_list.js index be85c586..30313a28 100644 --- a/core/user_list.js +++ b/core/user_list.js @@ -12,7 +12,7 @@ const _ = require('lodash'); /* Available listFormat/focusListFormat object members: - + userId : User ID userName : User name/handle lastLoginTs : Last login timestamp @@ -99,7 +99,7 @@ exports.getModule = class UserListModule extends MenuModule { userListView.redraw(); callback(null); } - ], + ], function complete(err) { if(err) { self.client.log.error( { error : err.toString() }, 'Error loading user list'); @@ -108,5 +108,5 @@ exports.getModule = class UserListModule extends MenuModule { } ); }); - } + } }; diff --git a/core/user_login.js b/core/user_login.js index 4bd9176c..37c3b306 100644 --- a/core/user_login.js +++ b/core/user_login.js @@ -39,8 +39,8 @@ function userLogin(client, username, password, cb) { if(existingClientConnection) { client.log.info( { - existingClientId : existingClientConnection.session.id, - username : user.username, + existingClientId : existingClientConnection.session.id, + username : user.username, userId : user.userId }, 'Already logged in' @@ -57,7 +57,7 @@ function userLogin(client, username, password, cb) { // update client logger with addition of username client.log = logger.log.child( { clientId : client.log.fields.clientId, username : user.username }); - client.log.info('Successful login'); + client.log.info('Successful login'); async.parallel( [ @@ -72,7 +72,7 @@ function userLogin(client, username, password, cb) { return StatLog.setUserStat(user, 'last_login_timestamp', StatLog.now, callback); }, function updateUserLoginCount(callback) { - return StatLog.incrementUserStat(user, 'login_count', 1, callback); + return StatLog.incrementUserStat(user, 'login_count', 1, callback); }, function recordLoginHistory(callback) { const LOGIN_HISTORY_MAX = 200; // history of up to last 200 callers diff --git a/core/uuid_util.js b/core/uuid_util.js index d8023f95..de64ec30 100644 --- a/core/uuid_util.js +++ b/core/uuid_util.js @@ -9,15 +9,15 @@ function createNamedUUID(namespaceUuid, key) { // // v5 UUID generation code based on the work here: // https://github.com/download13/uuidv5/blob/master/uuid.js - // + // if(!Buffer.isBuffer(namespaceUuid)) { namespaceUuid = new Buffer(namespaceUuid); } - + if(!Buffer.isBuffer(key)) { key = new Buffer(key); } - + let digest = createHash('sha1').update( Buffer.concat( [ namespaceUuid, key ] )).digest(); @@ -31,8 +31,8 @@ function createNamedUUID(namespaceUuid, key) { u[6] = (u[6] & 0x0f) | 0x50; // version, 4 most significant bits are set to version 5 (0101) u[8] = (digest[8] & 0x3f) | 0x80; // clock_seq_hi_and_reserved, 2msb are set to 10 u[9] = digest[9]; - + digest.copy(u, 10, 10, 16); - + return u; } \ No newline at end of file diff --git a/core/vertical_menu_view.js b/core/vertical_menu_view.js index 2cc2ad7a..847b9407 100644 --- a/core/vertical_menu_view.js +++ b/core/vertical_menu_view.js @@ -15,7 +15,7 @@ exports.VerticalMenuView = VerticalMenuView; function VerticalMenuView(options) { options.cursor = options.cursor || 'hide'; options.justify = options.justify || 'right'; // :TODO: default to center - + MenuView.call(this, options); const self = this; @@ -80,7 +80,7 @@ function VerticalMenuView(options) { self.client.term.write( ansi.goto(item.row, self.position.col) + - sgr + + sgr + strUtil.pad(text, this.dimens.width, this.fillChar, this.justify) ); }; @@ -89,7 +89,7 @@ function VerticalMenuView(options) { util.inherits(VerticalMenuView, MenuView); VerticalMenuView.prototype.redraw = function() { - VerticalMenuView.super_.prototype.redraw.call(this); + VerticalMenuView.super_.prototype.redraw.call(this); // :TODO: rename positionCacheExpired to something that makese sense; combine methods for such if(this.positionCacheExpired) { @@ -106,14 +106,14 @@ VerticalMenuView.prototype.redraw = function() { let seq = ansi.goto(this.position.row, this.position.col) + this.getSGR() + blank; let row = this.position.row + 1; const endRow = (row + this.oldDimens.height) - 2; - + while(row <= endRow) { seq += ansi.goto(row, this.position.col) + blank; row += 1; } this.client.term.write(seq); delete this.oldDimens; - } + } if(this.items.length) { let row = this.position.row; @@ -206,7 +206,7 @@ VerticalMenuView.prototype.removeItem = function(index) { VerticalMenuView.prototype.focusNext = function() { if(this.items.length - 1 === this.focusedItemIndex) { this.focusedItemIndex = 0; - + this.viewWindow = { top : 0, bottom : Math.min(this.maxVisibleItems, this.items.length) - 1 @@ -228,7 +228,7 @@ VerticalMenuView.prototype.focusNext = function() { VerticalMenuView.prototype.focusPrevious = function() { if(0 === this.focusedItemIndex) { this.focusedItemIndex = this.items.length - 1; - + this.viewWindow = { //top : this.items.length - this.maxVisibleItems, top : Math.max(this.items.length - this.maxVisibleItems, 0), @@ -279,7 +279,7 @@ VerticalMenuView.prototype.focusNextPageItem = function() { // // Jump to current + up to page size or bottom // If already at the bottom, jump to top - // + // if(this.items.length - 1 === this.focusedItemIndex) { return this.focusNext(); // will jump to top } diff --git a/core/view.js b/core/view.js index fccca541..1829f26d 100644 --- a/core/view.js +++ b/core/view.js @@ -39,7 +39,7 @@ function View(options) { var self = this; this.client = options.client; - + this.cursor = options.cursor || 'show'; this.cursorStyle = options.cursorStyle || 'default'; @@ -72,7 +72,7 @@ function View(options) { } else { this.dimens = { width : options.width || 0, - height : 0 + height : 0 }; } @@ -106,7 +106,7 @@ function View(options) { this.restoreCursor = function() { //this.client.term.write(ansi.setCursorStyle(this.cursorStyle)); this.client.term.rawWrite('show' === this.cursor ? ansi.showCursor() : ansi.hideCursor()); - }; + }; } util.inherits(View, events.EventEmitter); @@ -150,7 +150,7 @@ View.prototype.setDimension = function(dimens) { View.prototype.setHeight = function(height) { height = parseInt(height) || 1; - height = Math.min(height, this.client.term.termHeight); + height = Math.min(height, this.client.term.termHeight); this.dimens.height = height; this.autoScale.height = false; @@ -182,9 +182,9 @@ View.prototype.setPropertyValue = function(propName, value) { case 'height' : this.setHeight(value); break; case 'width' : this.setWidth(value); break; case 'focus' : this.setFocus(value); break; - - case 'text' : - if('setText' in this) { + + case 'text' : + if('setText' in this) { this.setText(value); } break; @@ -248,7 +248,7 @@ View.prototype.setFocus = function(focused) { this.restoreCursor(); }; -View.prototype.onKeyPress = function(ch, key) { +View.prototype.onKeyPress = function(ch, key) { enigAssert(this.hasFocus, 'View does not have focus'); enigAssert(this.acceptsInput, 'View does not accept input'); diff --git a/core/view_controller.js b/core/view_controller.js index ecf36be5..55b1bd1c 100644 --- a/core/view_controller.js +++ b/core/view_controller.js @@ -22,7 +22,7 @@ var MCI_REGEXP = /([A-Z]{2})([0-9]{1,2})/; function ViewController(options) { assert(_.isObject(options)); assert(_.isObject(options.client)); - + events.EventEmitter.call(this); var self = this; @@ -54,14 +54,14 @@ function ViewController(options) { self.client.log.warn( { err : err }, 'Error during handleAction()'); } } - + self.waitActionCompletion = false; }); }; this.clientKeyPressHandler = function(ch, key) { // - // Process key presses treating form submit mapped keys special. + // Process key presses treating form submit mapped keys special. // Everything else is forwarded on to the focused View, if any. // var actionForKey = key ? self.actionKeyMap[key.name] : self.actionKeyMap[ch]; @@ -92,7 +92,7 @@ function ViewController(options) { self.nextFocus(); break; - case 'accept' : + case 'accept' : if(self.focusedView && self.focusedView.submit) { // :TODO: need to do validation here!!! var focusedView = self.focusedView; @@ -166,37 +166,23 @@ function ViewController(options) { var propAsset; var propValue; - function callModuleMethod(path) { - if('' === paths.extname(path)) { - path += '.js'; - } - - try { - var methodMod = require(path); - // :TODO: fix formData & extraArgs - return methodMod[propAsset.asset](self.client.currentMenuModule, {}, {} ); - } catch(e) { - self.client.log.error( { error : e.toString(), methodName : propAsset.asset }, 'Failed to execute asset method'); - } - } - - for(var propName in conf) { + for(var propName in conf) { propAsset = asset.getViewPropertyAsset(conf[propName]); if(propAsset) { switch(propAsset.type) { case 'config' : - propValue = asset.resolveConfigAsset(conf[propName]); + propValue = asset.resolveConfigAsset(conf[propName]); break; - + case 'sysStat' : propValue = asset.resolveSystemStatAsset(conf[propName]); break; // :TODO: handle @art (e.g. text : @art ...) - case 'method' : + case 'method' : case 'systemMethod' : - if('validate' === propName) { + if('validate' === propName) { // :TODO: handle propAsset.location for @method script specification if('systemMethod' === propAsset.type) { // :TODO: implementation validation @systemMethod handling! @@ -211,7 +197,7 @@ function ViewController(options) { } } else { if(_.isString(propAsset.location)) { - + // :TODO: clean this code up! } else { if('systemMethod' === propAsset.type) { // :TODO: @@ -227,7 +213,7 @@ function ViewController(options) { } break; - default : + default : propValue = propValue = conf[propName]; break; } @@ -238,7 +224,7 @@ function ViewController(options) { if(!_.isUndefined(propValue)) { view.setPropertyValue(propName, propValue); } - } + } }; this.applyViewConfig = function(config, cb) { @@ -251,7 +237,7 @@ function ViewController(options) { if(null === mciMatch) { self.client.log.warn( { mci : mci }, 'Unable to parse MCI code'); return; - } + } var viewId = parseInt(mciMatch[2]); assert(!isNaN(viewId), 'Cannot parse view ID: ' + mciMatch[2]); // shouldn't be possible with RegExp used @@ -261,7 +247,7 @@ function ViewController(options) { } var view = self.getView(viewId); - + if(!view) { self.client.log.warn( { viewId : viewId }, 'Cannot find view'); nextItem(null); @@ -278,7 +264,7 @@ function ViewController(options) { nextItem(null); }, - function complete(err) { + function complete(err) { // default to highest ID if no 'submit' entry present if(!submitId) { var highestIdView = self.getView(highestId); @@ -310,7 +296,7 @@ function ViewController(options) { if(_.isUndefined(actionValue)) { return false; } - + if(_.isNumber(actionValue) || _.isString(actionValue)) { if(_.isUndefined(formValue[actionValue])) { return false; @@ -337,10 +323,10 @@ function ViewController(options) { } self.client.log.trace( - { + { formValue : formValue, actionValue : actionValue - }, + }, 'Action match' ); @@ -412,7 +398,7 @@ ViewController.prototype.detachClientEvents = function() { if(!this.attached) { return; } - + this.client.removeListener('key press', this.clientKeyPressHandler); for(var id in this.views) { @@ -465,7 +451,7 @@ ViewController.prototype.switchFocus = function(id) { self.validateView(focusedView, function validated(err, newFocusedViewId) { if(err) { - var newFocusedView = self.getView(newFocusedViewId) || focusedView; + var newFocusedView = self.getView(newFocusedViewId) || focusedView; self.setViewFocusWithEvents(newFocusedView, true); } else { self.attachClientEvents(); @@ -524,7 +510,7 @@ ViewController.prototype.setViewOrder = function(order) { ViewController.prototype.redrawAll = function(initialFocusId) { this.client.term.rawWrite(ansi.hideCursor()); - + for(var id in this.views) { if(initialFocusId === id) { continue; // will draw @ focus @@ -538,7 +524,7 @@ ViewController.prototype.redrawAll = function(initialFocusId) { ViewController.prototype.loadFromPromptConfig = function(options, cb) { assert(_.isObject(options)); assert(_.isObject(options.mciMap)); - + var self = this; var promptConfig = _.isObject(options.config) ? options.config : self.client.currentMenuModule.menuConfig.promptConfig; var initialFocusId = 1; // default to first @@ -560,7 +546,7 @@ ViewController.prototype.loadFromPromptConfig = function(options, cb) { callback(null); } }, - function prepareFormSubmission(callback) { + function prepareFormSubmission(callback) { if(false === self.noInput) { self.on('submit', function promptSubmit(formData) { @@ -610,7 +596,7 @@ ViewController.prototype.loadFromPromptConfig = function(options, cb) { // // * 'keys' must be present and be an array of key names // * If 'viewId' is present, key(s) will focus & submit on behalf - // of the specified view. + // of the specified view. // * If 'action' is present, that action will be procesed when // triggered by key(s) // @@ -681,7 +667,7 @@ ViewController.prototype.loadFromMenuConfig = function(options, cb) { callback(err); }); }, - /* + /* function applyThemeCustomization(callback) { formConfig = formConfig || {}; formConfig.mci = formConfig.mci || {}; @@ -701,7 +687,7 @@ ViewController.prototype.loadFromMenuConfig = function(options, cb) { //console.log('after theme...') //console.log(self.client.currentMenuModule.menuConfig.config) - + callback(null); }, */ @@ -764,7 +750,7 @@ ViewController.prototype.loadFromMenuConfig = function(options, cb) { // // * 'keys' must be present and be an array of key names // * If 'viewId' is present, key(s) will focus & submit on behalf - // of the specified view. + // of the specified view. // * If 'action' is present, that action will be procesed when // triggered by key(s) // @@ -807,7 +793,7 @@ ViewController.prototype.formatMCIString = function(format) { return format.replace(/{(\d+)}/g, function replacer(match, number) { view = self.getView(number); - + if(!view) { return match; } diff --git a/core/web_password_reset.js b/core/web_password_reset.js index c2d6852d..6ea1e6f8 100644 --- a/core/web_password_reset.js +++ b/core/web_password_reset.js @@ -13,13 +13,12 @@ const Log = require('./logger.js').log; // deps const async = require('async'); -const _ = require('lodash'); const crypto = require('crypto'); const fs = require('graceful-fs'); const url = require('url'); const querystring = require('querystring'); -const PW_RESET_EMAIL_TEXT_TEMPLATE_DEFAULT = +const PW_RESET_EMAIL_TEXT_TEMPLATE_DEFAULT = `%USERNAME%: a password reset has been requested for your account on %BOARDNAME%. @@ -46,7 +45,7 @@ class WebPasswordReset { } async.waterfall( - [ + [ function getEmailAddress(callback) { if(!username) { return callback(Errors.MissingParam('Missing "username"')); @@ -81,7 +80,7 @@ class WebPasswordReset { email_password_reset_token : token, email_password_reset_token_ts : getISOTimestampString(), }; - + // we simply place the reset token in the user's properties user.persistProperties(newProperties, err => { return callback(err, user); @@ -111,13 +110,13 @@ class WebPasswordReset { .replace(/%USERNAME%/g, user.username) .replace(/%TOKEN%/g, user.properties.email_password_reset_token) .replace(/%RESET_URL%/g, resetUrl) - ; + ; } textTemplate = replaceTokens(textTemplate); if(htmlTemplate) { htmlTemplate = replaceTokens(htmlTemplate); - } + } const message = { to : `${user.properties.display_name||user.username} <${user.properties.email_address}>`, @@ -128,7 +127,11 @@ class WebPasswordReset { }; sendMail(message, (err, info) => { - // :TODO: Log me! + if(err) { + Log.warn( { error : err.message }, 'Failed sending password reset email' ); + } else { + Log.debug( { info : info }, 'Successfully sent password reset email'); + } return callback(err); }); @@ -162,7 +165,7 @@ class WebPasswordReset { path : '^\\/reset_password\\?token\\=[a-f0-9]+$', // Config.contentServers.web.forgotPasswordPageTemplate handler : WebPasswordReset.routeResetPasswordGet, }, - // POST handler for performing the actual reset + // POST handler for performing the actual reset { method : 'POST', path : '^\\/reset_password$', diff --git a/core/whos_online.js b/core/whos_online.js index 6abd76ef..f832bc10 100644 --- a/core/whos_online.js +++ b/core/whos_online.js @@ -53,7 +53,7 @@ exports.getModule = class WhosOnlineModule extends MenuModule { const nonAuthUser = self.menuConfig.config.nonAuthUser || 'Logging In'; const otherUnknown = self.menuConfig.config.otherUnknown || 'N/A'; const onlineList = getActiveNodeList(self.menuConfig.config.authUsersOnly).slice(0, onlineListView.height); - + onlineListView.setItems(_.map(onlineList, oe => { if(oe.authenticated) { oe.timeOn = _.upperFirst(oe.timeOn.humanize()); diff --git a/core/word_wrap.js b/core/word_wrap.js index 0a4b122d..f246ad23 100644 --- a/core/word_wrap.js +++ b/core/word_wrap.js @@ -1,29 +1,31 @@ /* jslint node: true */ 'use strict'; -var assert = require('assert'); -var _ = require('lodash'); -const renderStringLength = require('./string_util.js').renderStringLength; +const renderStringLength = require('./string_util.js').renderStringLength; -exports.wordWrapText = wordWrapText2; +// deps +const assert = require('assert'); +const _ = require('lodash'); + +exports.wordWrapText = wordWrapText; const SPACE_CHARS = [ - ' ', '\f', '\n', '\r', '\v', + ' ', '\f', '\n', '\r', '\v', '​\u00a0', '\u1680', '​\u180e', '\u2000​', '\u2001', '\u2002', '​\u2003', '\u2004', - '\u2005', '\u2006​', '\u2007', '\u2008​', '\u2009', '\u200a​', '\u2028', '\u2029​', + '\u2005', '\u2006​', '\u2007', '\u2008​', '\u2009', '\u200a​', '\u2028', '\u2029​', '\u202f', '\u205f​', '\u3000', ]; -const REGEXP_WORD_WRAP = new RegExp(`\t|[${SPACE_CHARS.join('')}]`, 'g'); +const REGEXP_WORD_WRAP = new RegExp(`\t|[${SPACE_CHARS.join('')}]`, 'g'); -function wordWrapText2(text, options) { +function wordWrapText(text, options) { assert(_.isObject(options)); assert(_.isNumber(options.width)); - + options.tabHandling = options.tabHandling || 'expand'; options.tabWidth = options.tabWidth || 4; - options.tabChar = options.tabChar || ' '; - + options.tabChar = options.tabChar || ' '; + //const REGEXP_GOBBLE = new RegExp(`.{0,${options.width}}`, 'g'); // // For a given word, match 0->options.width chars -- alwasy include a full trailing ESC @@ -31,7 +33,7 @@ function wordWrapText2(text, options) { // // :TODO: Need to create ansi.getMatchRegex or something - this is used all over const REGEXP_GOBBLE = new RegExp(`.{0,${options.width}}\\x1b\\[[\\?=;0-9]*[ABCDEFGHJKLMSTfhlmnprsu]|.{0,${options.width}}`, 'g'); - + let m; let word; let c; @@ -39,30 +41,30 @@ function wordWrapText2(text, options) { let i = 0; let wordStart = 0; let result = { wrapped : [ '' ], renderLen : [] }; - + function expandTab(column) { const remainWidth = options.tabWidth - (column % options.tabWidth); return new Array(remainWidth).join(options.tabChar); } - + function appendWord() { word.match(REGEXP_GOBBLE).forEach( w => { renderLen = renderStringLength(w); - + if(result.renderLen[i] + renderLen > options.width) { if(0 === i) { result.firstWrapRange = { start : wordStart, end : wordStart + w.length }; } - + result.wrapped[++i] = w; result.renderLen[i] = renderLen; } else { - result.wrapped[i] += w; - result.renderLen[i] = (result.renderLen[i] || 0) + renderLen; + result.wrapped[i] += w; + result.renderLen[i] = (result.renderLen[i] || 0) + renderLen; } }); } - + // // Some of the way we word wrap is modeled after Sublime Test 3: // @@ -74,10 +76,10 @@ function wordWrapText2(text, options) { // "\t" may resolve to " " and must fit within the space. // // * If a word is ultimately too long to fit, break it up until it does. - // + // while(null !== (m = REGEXP_WORD_WRAP.exec(text))) { word = text.substring(wordStart, REGEXP_WORD_WRAP.lastIndex - 1); - + c = m[0].charAt(0); if(SPACE_CHARS.indexOf(c) > -1) { word += m[0]; @@ -89,129 +91,13 @@ function wordWrapText2(text, options) { word += m[0]; } } - + appendWord(); wordStart = REGEXP_WORD_WRAP.lastIndex + m[0].length - 1; } - + word = text.substring(wordStart); appendWord(); - + return result; } - -function wordWrapText(text, options) { - // - // options.*: - // width : word wrap width - // tabHandling : expand (default=expand) - // tabWidth : tab width if tabHandling is 'expand' (default=4) - // tabChar : character to use for tab expansion - // - assert(_.isObject(options), 'Missing options!'); - assert(_.isNumber(options.width), 'Missing options.width!'); - - options.tabHandling = options.tabHandling || 'expand'; - - if(!_.isNumber(options.tabWidth)) { - options.tabWidth = 4; - } - - options.tabChar = options.tabChar || ' '; - - // - // Notes - // * Sublime Text 3 for example considers spaces after a word - // part of said word. For example, "word " would be wraped - // in it's entirity. - // - // * Tabs in Sublime Text 3 are also treated as a word, so, e.g. - // "\t" may resolve to " " and must fit within the space. - // - // * If a word is ultimately too long to fit, break it up until it does. - // - // RegExp below is JavaScript '\s' minus the '\t' - // - var re = new RegExp( - '\t|[ \f\n\r\v​\u00a0\u1680​\u180e\u2000​\u2001\u2002​\u2003\u2004\u2005\u2006​' + - '\u2007\u2008​\u2009\u200a​\u2028\u2029​\u202f\u205f​\u3000]', 'g'); - var m; - var wordStart = 0; - var results = { wrapped : [ '' ] }; - var i = 0; - var word; - var wordLen; - - function expandTab(col) { - var remainWidth = options.tabWidth - (col % options.tabWidth); - return new Array(remainWidth).join(options.tabChar); - } - - // :TODO: support wrapping pipe code text (e.g. ignore color codes, expand MCI codes) - - function addWord() { - word.match(new RegExp('.{0,' + options.width + '}', 'g')).forEach(function wrd(w) { - //wordLen = self.getStringLength(w); - - if(results.wrapped[i].length + w.length > options.width) { - //if(results.wrapped[i].length + wordLen > width) { - if(0 === i) { - results.firstWrapRange = { start : wordStart, end : wordStart + w.length }; - //results.firstWrapRange = { start : wordStart, end : wordStart + wordLen }; - } - // :TODO: Must handle len of |w| itself > options.width & split how ever many times required (e.g. handle paste) - results.wrapped[++i] = w; - } else { - results.wrapped[i] += w; - } - }); - } - - while((m = re.exec(text)) !== null) { - word = text.substring(wordStart, re.lastIndex - 1); - - switch(m[0].charAt(0)) { - case ' ' : - word += m[0]; - break; - - case '\t' : - // - // Expand tab given position - // - // Nice info here: http://c-for-dummies.com/blog/?p=424 - // - if('expand' === options.tabHandling) { - word += expandTab(results.wrapped[i].length + word.length) + options.tabChar; - } else { - word += m[0]; - } - break; - } - - addWord(); - wordStart = re.lastIndex + m[0].length - 1; - } - - // - // Remainder - // - word = text.substring(wordStart); - addWord(); - - return results; -} - -//const input = 'Hello, |04World! This |08i|02s a test it is \x1b[20Conly a test of the emergency broadcast system. What you see is not a joke!'; -//const input = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five enturies, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."; - -/* -const iconv = require('iconv-lite'); -const input = iconv.decode(require('graceful-fs').readFileSync('/home/nuskooler/Downloads/msg_out.txt'), 'cp437'); - -const opts = { - width : 80, -}; - -console.log(wordWrapText2(input, opts).wrapped, 'utf8') -*/ \ No newline at end of file