diff --git a/core/bbs.js b/core/bbs.js index 816dfee6..36243227 100644 --- a/core/bbs.js +++ b/core/bbs.js @@ -223,15 +223,14 @@ function initialize(cb) { } function startListening(cb) { - if(!conf.config.servers) { + if(!conf.config.loginServers) { // :TODO: Log error ... output to stderr as well. We can do it all with the logger - //logger.log.error('No servers configured'); - return cb(new Error('No servers configured')); + return cb(new Error('No login servers configured')); } const moduleUtil = require('./module_util.js'); // late load so we get Config - moduleUtil.loadModulesForCategory('servers', (err, module) => { + moduleUtil.loadModulesForCategory('loginServers', (err, module) => { if(err) { if('EENIGMODDISABLED' === err.code) { logger.log.debug(err.message); diff --git a/core/client_term.js b/core/client_term.js index 8ef4753d..c9a9e66f 100644 --- a/core/client_term.js +++ b/core/client_term.js @@ -131,15 +131,16 @@ ClientTerminal.prototype.isANSI = function() { // ansi-bbs: // * fTelnet // + // pcansi: + // * ZOC + // // screen: // * ConnectBot (Android) // // linux: // * JuiceSSH (note: TERM=linux also) // - - // :TODO: Others?? - return [ 'ansi', 'pc-ansi', 'ansi-bbs', 'qansi', 'scoansi', 'syncterm' ].indexOf(this.termType) > -1; + return [ 'ansi', 'pcansi', 'pc-ansi', 'ansi-bbs', 'qansi', 'scoansi', 'syncterm' ].indexOf(this.termType) > -1; }; // :TODO: probably need to update these to convert IAC (0xff) -> IACIAC (escape it) diff --git a/core/config.js b/core/config.js index b6f92ded..c53f37f0 100644 --- a/core/config.js +++ b/core/config.js @@ -14,29 +14,29 @@ exports.init = init; exports.getDefaultPath = getDefaultPath; function hasMessageConferenceAndArea(config) { - assert(_.isObject(config.messageConferences)); // we create one ourself! - - const nonInternalConfs = Object.keys(config.messageConferences).filter(confTag => { - return 'system_internal' !== confTag; - }); - - if(0 === nonInternalConfs.length) { - return false; - } - - // :TODO: there is likely a better/cleaner way of doing this - - var result = false; - _.forEach(nonInternalConfs, confTag => { - if(_.has(config.messageConferences[confTag], 'areas') && - Object.keys(config.messageConferences[confTag].areas) > 0) - { - result = true; - return false; // stop iteration - } - }); - - return result; + assert(_.isObject(config.messageConferences)); // we create one ourself! + + const nonInternalConfs = Object.keys(config.messageConferences).filter(confTag => { + return 'system_internal' !== confTag; + }); + + if(0 === nonInternalConfs.length) { + return false; + } + + // :TODO: there is likely a better/cleaner way of doing this + + let result = false; + _.forEach(nonInternalConfs, confTag => { + if(_.has(config.messageConferences[confTag], 'areas') && + Object.keys(config.messageConferences[confTag].areas) > 0) + { + result = true; + return false; // stop iteration + } + }); + + return result; } function init(configPath, cb) { @@ -75,18 +75,18 @@ function init(configPath, cb) { // // Various sections must now exist in config // - if(hasMessageConferenceAndArea(mergedConfig)) { - var msgAreasErr = new Error('Please create at least one message conference and area!'); + if(hasMessageConferenceAndArea(mergedConfig)) { + var msgAreasErr = new Error('Please create at least one message conference and area!'); msgAreasErr.code = 'EBADCONFIG'; - callback(msgAreasErr); - } else { - callback(null, mergedConfig); - } + return callback(msgAreasErr); + } else { + return callback(null, mergedConfig); + } } ], function complete(err, mergedConfig) { exports.config = mergedConfig; - cb(err); + return cb(err); } ); } @@ -171,7 +171,8 @@ function getDefaultConfig() { paths : { mods : paths.join(__dirname, './../mods/'), - servers : paths.join(__dirname, './servers/'), + loginServers : paths.join(__dirname, './servers/login/'), + contentServers : paths.join(__dirname, './servers/content/'), scannerTossers : paths.join(__dirname, './scanner_tossers/'), mailers : paths.join(__dirname, './mailers/') , @@ -185,7 +186,7 @@ function getDefaultConfig() { misc : paths.join(__dirname, './../misc/'), }, - servers : { + loginServers : { telnet : { port : 8888, enabled : true, @@ -266,6 +267,23 @@ function getDefaultConfig() { bundleTargetByteSize : 2048000, // 2M, before creating another archive } }, + + fileBase: { + // areas with an explicit |storageDir| will be stored relative to |areaStoragePrefix|: + areaStoragePrefix : paths.join(__dirname, './../file_base/'), + + fileNamePatterns: { + shortDesc : [ '^FILE_ID\.DIZ$', '^DESC\.SDI$' ], + longDesc : [ '^.*\.NFO$', '^README\.1ST$', '^README\.TXT$' ], + }, + + areas: { + message_attachment : { + name : 'Message attachments', + desc : 'File attachments to messages', + } + } + }, eventScheduler : { diff --git a/core/database.js b/core/database.js index b6437cf5..e5e74571 100644 --- a/core/database.js +++ b/core/database.js @@ -47,233 +47,273 @@ function getModDatabasePath(moduleInfo, suffix) { } function initializeDatabases(cb) { - async.series( - [ - function systemDb(callback) { - dbs.system = new sqlite3.Database(getDatabasePath('system'), err => { - if(err) { - return callback(err); - } - - dbs.system.serialize( () => { - createSystemTables(); - }); - - return callback(null); - }); - }, - function userDb(callback) { - dbs.user = new sqlite3.Database(getDatabasePath('user'), err => { - if(err) { - return callback(err); - } - - dbs.user.serialize( () => { - createUserTables(); - createInitialUserValues(); - }); - - return callback(null); - }); - }, - function messageDb(callback) { - dbs.message = new sqlite3.Database(getDatabasePath('message'), err => { - if(err) { - return callback(err); - } - - - dbs.message.serialize(function serialized() { - createMessageBaseTables(); - createInitialMessageValues(); - }); - - return callback(null); - }); + async.each( [ 'system', 'user', 'message', 'file' ], (dbName, next) => { + dbs[dbName] = new sqlite3.Database(getDatabasePath(dbName), err => { + if(err) { + return cb(err); } - ], - cb - ); + + dbs[dbName].serialize( () => { + DB_INIT_TABLE[dbName](); + + return next(null); + }); + }); + }, err => { + return cb(err); + }); } -function createSystemTables() { +const DB_INIT_TABLE = { + system : () => { + dbs.system.run('PRAGMA foreign_keys = ON;'); - dbs.system.run('PRAGMA foreign_keys = ON;'); + // Various stat/event logging - see stat_log.js + dbs.system.run( + `CREATE TABLE IF NOT EXISTS system_stat ( + stat_name VARCHAR PRIMARY KEY NOT NULL, + stat_value VARCHAR NOT NULL + );` + ); - // Various stat/event logging - see stat_log.js - dbs.system.run( - `CREATE TABLE IF NOT EXISTS system_stat ( - stat_name VARCHAR PRIMARY KEY NOT NULL, - stat_value VARCHAR NOT NULL - );` - ); + dbs.system.run( + `CREATE TABLE IF NOT EXISTS system_event_log ( + id INTEGER PRIMARY KEY, + timestamp DATETIME NOT NULL, + log_name VARCHAR NOT NULL, + log_value VARCHAR NOT NULL, - dbs.system.run( - `CREATE TABLE IF NOT EXISTS system_event_log ( - id INTEGER PRIMARY KEY, - timestamp DATETIME NOT NULL, - log_name VARCHAR NOT NULL, - log_value VARCHAR NOT NULL, + UNIQUE(timestamp, log_name) + );` + ); - UNIQUE(timestamp, log_name) - );` - ); + dbs.system.run( + `CREATE TABLE IF NOT EXISTS user_event_log ( + id INTEGER PRIMARY KEY, + timestamp DATETIME NOT NULL, + user_id INTEGER NOT NULL, + log_name VARCHAR NOT NULL, + log_value VARCHAR NOT NULL, - dbs.system.run( - `CREATE TABLE IF NOT EXISTS user_event_log ( - id INTEGER PRIMARY KEY, - timestamp DATETIME NOT NULL, - user_id INTEGER NOT NULL, - log_name VARCHAR NOT NULL, - log_value VARCHAR NOT NULL, + UNIQUE(timestamp, user_id, log_name) + );` + ); + }, - UNIQUE(timestamp, user_id, log_name) - );` - ); -} + user : () => { + dbs.user.run('PRAGMA foreign_keys = ON;'); -function createUserTables() { - dbs.user.run('PRAGMA foreign_keys = ON;'); + dbs.user.run( + `CREATE TABLE IF NOT EXISTS user ( + id INTEGER PRIMARY KEY, + user_name VARCHAR NOT NULL, + UNIQUE(user_name) + );` + ); - dbs.user.run( - `CREATE TABLE IF NOT EXISTS user ( - id INTEGER PRIMARY KEY, - user_name VARCHAR NOT NULL, - UNIQUE(user_name) - );` - ); + // :TODO: create FK on delete/etc. - // :TODO: create FK on delete/etc. + dbs.user.run( + `CREATE TABLE IF NOT EXISTS user_property ( + user_id INTEGER NOT NULL, + prop_name VARCHAR NOT NULL, + prop_value VARCHAR, + UNIQUE(user_id, prop_name), + FOREIGN KEY(user_id) REFERENCES user(id) ON DELETE CASCADE + );` + ); - dbs.user.run( - `CREATE TABLE IF NOT EXISTS user_property ( - user_id INTEGER NOT NULL, - prop_name VARCHAR NOT NULL, - prop_value VARCHAR, - UNIQUE(user_id, prop_name), - FOREIGN KEY(user_id) REFERENCES user(id) ON DELETE CASCADE - );` - ); + dbs.user.run( + `CREATE TABLE IF NOT EXISTS user_group_member ( + group_name VARCHAR NOT NULL, + user_id INTEGER NOT NULL, + UNIQUE(group_name, user_id) + );` + ); - dbs.user.run( - `CREATE TABLE IF NOT EXISTS user_group_member ( - group_name VARCHAR NOT NULL, - user_id INTEGER NOT NULL, - UNIQUE(group_name, user_id) - );` - ); + dbs.user.run( + `CREATE TABLE IF NOT EXISTS user_login_history ( + user_id INTEGER NOT NULL, + user_name VARCHAR NOT NULL, + timestamp DATETIME NOT NULL + );` + ); + }, - dbs.user.run( - `CREATE TABLE IF NOT EXISTS user_login_history ( - user_id INTEGER NOT NULL, - user_name VARCHAR NOT NULL, - timestamp DATETIME NOT NULL - );` - ); -} + message : () => { + dbs.message.run('PRAGMA foreign_keys = ON;'); -function createMessageBaseTables() { + dbs.message.run( + `CREATE TABLE IF NOT EXISTS message ( + message_id INTEGER PRIMARY KEY, + area_tag VARCHAR NOT NULL, + message_uuid VARCHAR(36) NOT NULL, + reply_to_message_id INTEGER, + to_user_name VARCHAR NOT NULL, + from_user_name VARCHAR NOT NULL, + subject, /* FTS @ message_fts */ + message, /* FTS @ message_fts */ + modified_timestamp DATETIME NOT NULL, + view_count INTEGER NOT NULL DEFAULT 0, + UNIQUE(message_uuid) + );` + ); - dbs.message.run('PRAGMA foreign_keys = ON;'); + dbs.message.run( + `CREATE INDEX IF NOT EXISTS message_by_area_tag_index + ON message (area_tag);` + ); - dbs.message.run( - `CREATE TABLE IF NOT EXISTS message ( - message_id INTEGER PRIMARY KEY, - area_tag VARCHAR NOT NULL, - message_uuid VARCHAR(36) NOT NULL, - reply_to_message_id INTEGER, - to_user_name VARCHAR NOT NULL, - from_user_name VARCHAR NOT NULL, - subject, /* FTS @ message_fts */ - message, /* FTS @ message_fts */ - modified_timestamp DATETIME NOT NULL, - view_count INTEGER NOT NULL DEFAULT 0, - UNIQUE(message_uuid) - );` - ); + dbs.message.run( + `CREATE VIRTUAL TABLE IF NOT EXISTS message_fts USING fts4 ( + content="message", + subject, + message + );` + ); - dbs.message.run( - `CREATE INDEX IF NOT EXISTS message_by_area_tag_index - ON message (area_tag);` - ); + dbs.message.run( + `CREATE TRIGGER IF NOT EXISTS message_before_update BEFORE UPDATE ON message BEGIN + DELETE FROM message_fts WHERE docid=old.rowid; + END; + + CREATE TRIGGER IF NOT EXISTS message_before_delete BEFORE DELETE ON message BEGIN + DELETE FROM message_fts WHERE docid=old.rowid; + END; - dbs.message.run( - `CREATE VIRTUAL TABLE IF NOT EXISTS message_fts USING fts4 ( - content="message", - subject, - message - );` - ); + CREATE TRIGGER IF NOT EXISTS message_after_update AFTER UPDATE ON message BEGIN + INSERT INTO message_fts(docid, subject, message) VALUES(new.rowid, new.subject, new.message); + END; - dbs.message.run( - `CREATE TRIGGER IF NOT EXISTS message_before_update BEFORE UPDATE ON message BEGIN - DELETE FROM message_fts WHERE docid=old.rowid; - END; + CREATE TRIGGER IF NOT EXISTS message_after_insert AFTER INSERT ON message BEGIN + INSERT INTO message_fts(docid, subject, message) VALUES(new.rowid, new.subject, new.message); + END;` + ); + + dbs.message.run( + `CREATE TABLE IF NOT EXISTS message_meta ( + message_id INTEGER NOT NULL, + meta_category INTEGER NOT NULL, + meta_name VARCHAR NOT NULL, + meta_value VARCHAR NOT NULL, + UNIQUE(message_id, meta_category, meta_name, meta_value), + FOREIGN KEY(message_id) REFERENCES message(message_id) ON DELETE CASCADE + );` + ); + + // :TODO: need SQL to ensure cleaned up if delete from message? + /* + dbs.message.run( + `CREATE TABLE IF NOT EXISTS hash_tag ( + hash_tag_id INTEGER PRIMARY KEY, + hash_tag_name VARCHAR NOT NULL, + UNIQUE(hash_tag_name) + );` + ); + + // :TODO: need SQL to ensure cleaned up if delete from message? + dbs.message.run( + `CREATE TABLE IF NOT EXISTS message_hash_tag ( + hash_tag_id INTEGER NOT NULL, + message_id INTEGER NOT NULL, + );` + ); + */ + + dbs.message.run( + `CREATE TABLE IF NOT EXISTS user_message_area_last_read ( + user_id INTEGER NOT NULL, + area_tag VARCHAR NOT NULL, + message_id INTEGER NOT NULL, + UNIQUE(user_id, area_tag) + );` + ); - CREATE TRIGGER IF NOT EXISTS message_before_delete BEFORE DELETE ON message BEGIN - DELETE FROM message_fts WHERE docid=old.rowid; - END; + 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) + );` + ); + }, - CREATE TRIGGER IF NOT EXISTS message_after_update AFTER UPDATE ON message BEGIN - INSERT INTO message_fts(docid, subject, message) VALUES(new.rowid, new.subject, new.message); - END; + file : () => { + dbs.file.run('PRAGMA foreign_keys = ON;'); - CREATE TRIGGER IF NOT EXISTS message_after_insert AFTER INSERT ON message BEGIN - INSERT INTO message_fts(docid, subject, message) VALUES(new.rowid, new.subject, new.message); - END;` - ); + dbs.file.run( + // :TODO: should any of this be unique?? + `CREATE TABLE IF NOT EXISTS file ( + file_id INTEGER PRIMARY KEY, + area_tag VARCHAR NOT NULL, + file_sha1 VARCHAR NOT NULL, + file_name, /* FTS @ file_fts */ + desc, /* FTS @ file_fts */ + desc_long, /* FTS @ file_fts */ + upload_by_username VARCHAR NOT NULL, + upload_timestamp DATETIME NOT NULL + );` + ); - dbs.message.run( - `CREATE TABLE IF NOT EXISTS message_meta ( - message_id INTEGER NOT NULL, - meta_category INTEGER NOT NULL, - meta_name VARCHAR NOT NULL, - meta_value VARCHAR NOT NULL, - UNIQUE(message_id, meta_category, meta_name, meta_value), - FOREIGN KEY(message_id) REFERENCES message(message_id) ON DELETE CASCADE - );` - ); + dbs.file.run( + `CREATE INDEX IF NOT EXISTS file_by_area_tag_index + ON file (area_tag);` + ); - // :TODO: need SQL to ensure cleaned up if delete from message? - /* - dbs.message.run( - `CREATE TABLE IF NOT EXISTS hash_tag ( - hash_tag_id INTEGER PRIMARY KEY, - hash_tag_name VARCHAR NOT NULL, - UNIQUE(hash_tag_name) - );` - ); + dbs.file.run( + `CREATE VIRTUAL TABLE IF NOT EXISTS file_fts USING fts4 ( + content="file", + file_name, + desc, + desc_long + );` + ); - // :TODO: need SQL to ensure cleaned up if delete from message? - dbs.message.run( - `CREATE TABLE IF NOT EXISTS message_hash_tag ( - hash_tag_id INTEGER NOT NULL, - message_id INTEGER NOT NULL, - );` - ); - */ + dbs.file.run( + `CREATE TRIGGER IF NOT EXISTS file_before_update BEFORE UPDATE ON file BEGIN + DELETE FROM file_fts WHERE docid=old.rowid; + END; + + CREATE TRIGGER IF NOT EXISTS file_before_delete BEFORE DELETE ON file BEGIN + DELETE FROM file_fts WHERE docid=old.rowid; + END; - dbs.message.run( - `CREATE TABLE IF NOT EXISTS user_message_area_last_read ( - user_id INTEGER NOT NULL, - area_tag VARCHAR NOT NULL, - message_id INTEGER NOT NULL, - 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) - );` - ); -} + CREATE TRIGGER IF NOT EXISTS file_after_update AFTER UPDATE ON file BEGIN + INSERT INTO file_fts(docid, file_name, desc, long_desc) VALUES(new.rowid, new.file_name, new.desc, new.long_desc); + END; -function createInitialMessageValues() { -} + CREATE TRIGGER IF NOT EXISTS file_after_insert AFTER INSERT ON file BEGIN + INSERT INTO file_fts(docid, file_name, desc, desc_long) VALUES(new.rowid, new.file_name, new.desc, new.long_desc); + END;` + ); -function createInitialUserValues() { -} \ No newline at end of file + dbs.file.run( + `CREATE TABLE IF NOT EXISTS file_meta ( + file_id INTEGER NOT NULL, + meta_name VARCHAR NOT NULL, + meta_value VARCHAR NOT NULL, + UNIQUE(file_id, meta_name, meta_value), + FOREIGN KEY(file_id) REFERENCES file(file_id) ON DELETE CASCADE + );` + ); + + dbs.file.run( + `CREATE TABLE IF NOT EXISTS hash_tag ( + hash_tag_id INTEGER PRIMARY KEY, + hash_tag VARCHAR NOT NULL, + + UNIQUE(hash_tag) + );` + ); + + dbs.file.run( + `CREATE TABLE IF NOT EXISTS file_hash_tag ( + hash_tag_id INTEGER NOT NULL, + file_id INTEGER NOT NULL, + + UNIQUE(hash_tag_id, file_id) + );` + ); + } +}; \ No newline at end of file diff --git a/core/enig_error.js b/core/enig_error.js index 69722a85..adf5eef6 100644 --- a/core/enig_error.js +++ b/core/enig_error.js @@ -2,11 +2,14 @@ 'use strict'; class EnigError extends Error { - constructor(message) { + constructor(message, code, reason, reasonCode) { super(message); this.name = this.constructor.name; this.message = message; + this.code = code; + this.reason = reason; + this.reasonCode = reasonCode; if(typeof Error.captureStackTrace === 'function') { Error.captureStackTrace(this, this.constructor); @@ -16,4 +19,12 @@ class EnigError extends Error { } } -exports.EnigError = EnigError; \ No newline at end of file +class EnigMenuError extends EnigError { } + +exports.EnigError = EnigError; +exports.EnigMenuError = EnigMenuError; + +exports.Errors = { + General : (reason, reasonCode) => new EnigError('An error occurred', -33000, reason, reasonCode), + MenuStack : (reason, reasonCode) => new EnigMenuError('Menu stack error', -33001, reason, reasonCode), +}; diff --git a/core/fse.js b/core/fse.js index 414c10ef..0afc31c1 100644 --- a/core/fse.js +++ b/core/fse.js @@ -8,6 +8,7 @@ const ansi = require('./ansi_term.js'); const theme = require('./theme.js'); const Message = require('./message.js'); const updateMessageAreaLastReadId = require('./message_area.js').updateMessageAreaLastReadId; +const getMessageAreaByTag = require('./message_area.js').getMessageAreaByTag; const getUserIdAndName = require('./user.js').getUserIdAndName; const cleanControlCodes = require('./string_util.js').cleanControlCodes; const StatLog = require('./stat_log.js'); @@ -563,8 +564,14 @@ function FullScreenEditorModule(options) { break; case 'edit' : - self.viewControllers.header.getView(1).setText(self.client.user.username); // from - + const fromView = self.viewControllers.header.getView(1); + const area = getMessageAreaByTag(self.messageAreaTag); + if(area && area.realNames) { + fromView.setText(self.client.user.properties.real_name || self.client.user.username); + } else { + fromView.setText(self.client.user.username); + } + if(self.replyToMessage) { self.initHeaderReplyEditMode(); } diff --git a/core/menu_stack.js b/core/menu_stack.js index 98a171b9..84e6a6e0 100644 --- a/core/menu_stack.js +++ b/core/menu_stack.js @@ -3,6 +3,7 @@ // ENiGMA½ const loadMenu = require('./menu_util.js').loadMenu; +const Errors = require('./enig_error.js').Errors; // deps const _ = require('lodash'); @@ -57,16 +58,16 @@ module.exports = class MenuStack { if(_.isArray(menuConfig.next)) { nextMenu = this.client.acs.getConditionalValue(menuConfig.next, 'next'); if(!nextMenu) { - return cb(new Error('No matching condition for \'next\'!')); + return cb(Errors.MenuStack('No matching condition for "next"', 'NOCONDMATCH')); } } else if(_.isString(menuConfig.next)) { nextMenu = menuConfig.next; } else { - return cb(new Error('Invalid or missing \'next\' member in menu config!')); + return cb(Errors.MenuStack('Invalid or missing "next" member in menu config', 'BADNEXT')); } if(nextMenu === currentModuleInfo.name) { - return cb(new Error('Menu config \'next\' specifies current menu!')); + return cb(Errors.MenuStack('Menu config "next" specifies current menu', 'ALREADYTHERE')); } this.goto(nextMenu, { }, cb); @@ -90,7 +91,7 @@ module.exports = class MenuStack { return this.goto(previousModuleInfo.name, opts, cb); } - return cb(new Error('No previous menu available!')); + return cb(Errors.MenuStack('No previous menu available', 'NOPREV')); } goto(name, options, cb) { @@ -104,7 +105,7 @@ module.exports = class MenuStack { if(currentModuleInfo && name === currentModuleInfo.name) { if(cb) { - cb(new Error('Already at supplied menu!')); + cb(Errors.MenuStack('Already at supplied menu', 'ALREADYTHERE')); } return; } diff --git a/core/message.js b/core/message.js index ff13a84a..e1d3e4fd 100644 --- a/core/message.js +++ b/core/message.js @@ -139,7 +139,7 @@ Message.createMessageUUID = function(areaTag, modTimestamp, subject, body) { body = iconvEncode(body.replace(/\r\n|[\n\v\f\r\x85\u2028\u2029]/g, '').trim(), 'CP437'); return uuid.unparse(createNamedUUID(ENIGMA_MESSAGE_UUID_NAMESPACE, Buffer.concat( [ areaTag, modTimestamp, subject, body ] ))); -} +}; Message.getMessageIdByUuid = function(uuid, cb) { msgDb.get( @@ -351,13 +351,13 @@ Message.prototype.persist = function(cb) { return cb(new Error('Cannot persist invalid message!')); } - let self = this; + const self = this; async.series( [ function beginTransaction(callback) { Message.startTransaction(err => { - callback(err); + return callback(err); }); }, function storeMessage(callback) { @@ -375,53 +375,52 @@ Message.prototype.persist = function(cb) { `INSERT INTO message (area_tag, message_uuid, reply_to_message_id, to_user_name, from_user_name, subject, message, modified_timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?);`, [ self.areaTag, self.uuid, self.replyToMsgId, self.toUserName, self.fromUserName, self.subject, self.message, self.getMessageTimestampString(msgTimestamp) ], - function inserted(err) { // use for this scope + function inserted(err) { // use non-arrow function for 'this' scope if(!err) { self.messageId = this.lastID; } - callback(err); + return callback(err); } ); }, function storeMeta(callback) { if(!self.meta) { - callback(null); - } else { - /* - Example of self.meta: - - meta: { - System: { - 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) => { - self.persistMetaValue(category, name, self.meta[category][name], err => { - nextName(err); - }); - }, err => { - nextCat(err); - }); - - }, err => { - callback(err); - }); + return callback(null); } + /* + Example of self.meta: + + meta: { + System: { + 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) => { + self.persistMetaValue(category, name, self.meta[category][name], err => { + nextName(err); + }); + }, err => { + nextCat(err); + }); + + }, err => { + callback(err); + }); }, function storeHashTags(callback) { // :TODO: hash tag support - callback(null); + return callback(null); } ], err => { Message.endTransaction(err, transErr => { - cb(err ? err : transErr, self.messageId); + return cb(err ? err : transErr, self.messageId); }); } ); diff --git a/core/message_area.js b/core/message_area.js index 1a272a58..2f74357b 100644 --- a/core/message_area.js +++ b/core/message_area.js @@ -560,10 +560,10 @@ function persistMessage(message, cb) { async.series( [ function persistMessageToDisc(callback) { - message.persist(callback); + return message.persist(callback); }, function recordToMessageNetworks(callback) { - msgNetRecord(message, callback); + return msgNetRecord(message, callback); } ], cb diff --git a/core/scanner_tossers/ftn_bso.js b/core/scanner_tossers/ftn_bso.js index 30cb0933..b5e65227 100644 --- a/core/scanner_tossers/ftn_bso.js +++ b/core/scanner_tossers/ftn_bso.js @@ -1216,8 +1216,9 @@ FTNMessageScanTossModule.prototype.startup = function(cb) { if(exportSchedule) { Log.debug( { - schedule : this.moduleConfig.schedule.export, + schedule : this.moduleConfig.schedule.export, schedOK : -1 === exportSchedule.sched.error, + next : moment(later.schedule(exportSchedule.sched).next(1)).format('ddd, MMM Do, YYYY @ h:m:ss a'), immediate : exportSchedule.immediate ? true : false, }, 'Export schedule loaded' @@ -1245,6 +1246,7 @@ FTNMessageScanTossModule.prototype.startup = function(cb) { { schedule : this.moduleConfig.schedule.import, schedOK : -1 === importSchedule.sched.error, + next : moment(later.schedule(importSchedule.sched).next(1)).format('ddd, MMM Do, YYYY @ h:m:ss a'), watchFile : _.isString(importSchedule.watchFile) ? importSchedule.watchFile : 'None', }, 'Import schedule loaded' diff --git a/core/servers/ssh.js b/core/servers/login/ssh.js similarity index 89% rename from core/servers/ssh.js rename to core/servers/login/ssh.js index d60d821e..1abd1e84 100644 --- a/core/servers/ssh.js +++ b/core/servers/login/ssh.js @@ -2,14 +2,14 @@ 'use strict'; // ENiGMA½ -const Config = require('../config.js').config; -const baseClient = require('../client.js'); -const Log = require('../logger.js').log; -const ServerModule = require('../server_module.js').ServerModule; -const userLogin = require('../user_login.js').userLogin; -const enigVersion = require('../../package.json').version; -const theme = require('../theme.js'); -const stringFormat = require('../string_format.js'); +const Config = require('../../config.js').config; +const baseClient = require('../../client.js'); +const Log = require('../../logger.js').log; +const ServerModule = require('../../server_module.js').ServerModule; +const userLogin = require('../../user_login.js').userLogin; +const enigVersion = require('../../../package.json').version; +const theme = require('../../theme.js'); +const stringFormat = require('../../string_format.js'); // deps const ssh2 = require('ssh2'); @@ -200,7 +200,7 @@ function SSHClient(clientConn) { } // we're ready! - const firstMenu = self.isNewUser ? Config.servers.ssh.firstMenuNewUser : Config.servers.ssh.firstMenu; + const firstMenu = self.isNewUser ? Config.loginServers.ssh.firstMenuNewUser : Config.loginServers.ssh.firstMenu; self.emit('ready', { firstMenu : firstMenu } ); }); @@ -238,15 +238,15 @@ SSHServerModule.prototype.createServer = function() { const serverConf = { hostKeys : [ { - key : fs.readFileSync(Config.servers.ssh.privateKeyPem), - passphrase : Config.servers.ssh.privateKeyPass, + key : fs.readFileSync(Config.loginServers.ssh.privateKeyPem), + passphrase : Config.loginServers.ssh.privateKeyPass, } ], ident : 'enigma-bbs-' + enigVersion + '-srv', // Note that sending 'banner' breaks at least EtherTerm! debug : (sshDebugLine) => { - if(true === Config.servers.ssh.traceConnections) { + if(true === Config.loginServers.ssh.traceConnections) { Log.trace(`SSH: ${sshDebugLine}`); } }, diff --git a/core/servers/telnet.js b/core/servers/login/telnet.js similarity index 98% rename from core/servers/telnet.js rename to core/servers/login/telnet.js index 0e174a57..7573e62e 100644 --- a/core/servers/telnet.js +++ b/core/servers/login/telnet.js @@ -2,10 +2,10 @@ 'use strict'; // ENiGMA½ -const baseClient = require('../client.js'); -const Log = require('../logger.js').log; -const ServerModule = require('../server_module.js').ServerModule; -const Config = require('../config.js').config; +const baseClient = require('../../client.js'); +const Log = require('../../logger.js').log; +const ServerModule = require('../../server_module.js').ServerModule; +const Config = require('../../config.js').config; // deps const net = require('net'); @@ -497,7 +497,7 @@ function TelnetClient(input, output) { }); this.connectionDebug = (info, msg) => { - if(Config.servers.telnet.traceConnections) { + if(Config.loginServers.telnet.traceConnections) { self.log.trace(info, 'Telnet: ' + msg); } }; @@ -584,7 +584,7 @@ TelnetClient.prototype.handleSbCommand = function(evt) { if(!self.didReady) { self.didReady = true; - self.emit('ready', { firstMenu : Config.servers.telnet.firstMenu } ); + self.emit('ready', { firstMenu : Config.loginServers.telnet.firstMenu } ); } } else if('new environment' === evt.option) { // diff --git a/core/view_controller.js b/core/view_controller.js index dcc25d31..f2fbb366 100644 --- a/core/view_controller.js +++ b/core/view_controller.js @@ -49,7 +49,11 @@ function ViewController(options) { menuUtil.handleAction(self.client, formData, actionBlock, (err) => { if(err) { // :TODO: What can we really do here? - self.client.log.warn( { err : err }, 'Error during handleAction()'); + if('ALREADYTHERE' === err.reasonCode) { + self.client.log.trace( err.reason ); + } else { + self.client.log.warn( { err : err }, 'Error during handleAction()'); + } } self.waitActionCompletion = false;