Merge branch 'master' of ssh://numinibsd/git/base/enigma-bbs
This commit is contained in:
commit
d1653d620d
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 : {
|
||||
|
||||
|
|
440
core/database.js
440
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() {
|
||||
}
|
||||
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)
|
||||
);`
|
||||
);
|
||||
}
|
||||
};
|
|
@ -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),
|
||||
};
|
||||
|
|
11
core/fse.js
11
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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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}`);
|
||||
}
|
||||
},
|
|
@ -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) {
|
||||
//
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue