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

This commit is contained in:
Bryan Ashby 2016-10-03 20:49:38 -06:00
commit d1653d620d
13 changed files with 385 additions and 303 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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 : {

View File

@ -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() {
}
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)
);`
);
}
};

View File

@ -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;
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),
};

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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);
});
}
);

View File

@ -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

View File

@ -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'

View File

@ -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}`);
}
},

View File

@ -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) {
//

View File

@ -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;