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

This commit is contained in:
Bryan Ashby 2016-01-02 13:35:47 -07:00
commit cb223f17f5
9 changed files with 212 additions and 18 deletions

View File

@ -18,6 +18,7 @@ function addNewClient(client, clientSock) {
var id = client.session.id = clientConnections.push(client) - 1;
// Create a client specific logger
// Note that this will be updated @ login with additional information
client.log = logger.log.child( { clientId : id } );
var connInfo = {

View File

@ -144,21 +144,23 @@ ClientTerminal.prototype.isANSI = function() {
// :TODO: probably need to update these to convert IAC (0xff) -> IACIAC (escape it)
ClientTerminal.prototype.write = function(s, convertLineFeeds) {
this.rawWrite(this.encode(s, convertLineFeeds));
ClientTerminal.prototype.write = function(s, convertLineFeeds, cb) {
this.rawWrite(this.encode(s, convertLineFeeds), cb);
};
ClientTerminal.prototype.rawWrite = function(s) {
ClientTerminal.prototype.rawWrite = function(s, cb) {
if(this.output) {
this.output.write(s, function written(err) {
if(err) {
if(_.isFunction(cb)) {
cb(err);
} else if(err) {
Log.warn('Failed writing to socket: ' + err.toString());
}
});
}
};
ClientTerminal.prototype.pipeWrite = function(s, spec) {
ClientTerminal.prototype.pipeWrite = function(s, spec, cb) {
spec = spec || 'renegade';
var conv = {
@ -166,11 +168,12 @@ ClientTerminal.prototype.pipeWrite = function(s, spec) {
renegade : renegadeToAnsi,
}[spec] || enigmaToAnsi;
this.write(conv(s, this));
this.write(conv(s, this), null, cb); // null = use default for |convertLineFeeds|
};
ClientTerminal.prototype.encode = function(s, convertLineFeeds) {
convertLineFeeds = _.isUndefined(convertLineFeeds) ? this.convertLF : convertLineFeeds;
convertLineFeeds = _.isBoolean(convertLineFeeds) ? convertLineFeeds : this.convertLF;
if(convertLineFeeds && _.isString(s)) {
s = s.replace(/\n/g, '\r\n');
}

View File

@ -81,8 +81,9 @@ function Message(options) {
}
Message.WellKnownAreaNames = {
Invalid : '',
Private : 'private_mail'
Invalid : '',
Private : 'private_mail',
Bulletin : 'local_bulletin',
};
// :TODO: This doesn't seem like a good way to go -- perhaps only for local/user2user, or just use

View File

@ -14,6 +14,7 @@ exports.getDefaultMessageArea = getDefaultMessageArea;
exports.getMessageAreaByName = getMessageAreaByName;
exports.changeMessageArea = changeMessageArea;
exports.getMessageListForArea = getMessageListForArea;
exports.getNewMessagesInAreaForUser = getNewMessagesInAreaForUser;
exports.getMessageAreaLastReadId = getMessageAreaLastReadId;
exports.updateMessageAreaLastReadId = updateMessageAreaLastReadId;
@ -104,6 +105,60 @@ function changeMessageArea(client, areaName, cb) {
);
}
function getNewMessagesInAreaForUser(userId, areaName, cb) {
//
// If |areaName| is Message.WellKnownAreaNames.Private,
// only messages addressed to |userId| should be returned.
//
// Only messages > lastMessageId should be returned
//
var msgList = [];
async.waterfall(
[
function getLastMessageId(callback) {
getMessageAreaLastReadId(userId, areaName, function fetched(err, lastMessageId) {
callback(null, lastMessageId || 0); // note: willingly ignoring any errors here!
});
},
function getMessages(lastMessageId, callback) {
var 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_name="' + areaName + '" AND message_id > ' + lastMessageId;
if(Message.WellKnownAreaNames.Private === areaName) {
sql +=
' AND message_id in (' +
'SELECT message_id from message_meta where meta_category=' + Message.MetaCategories.System +
' AND meta_name="' + Message.SystemMetaNames.LocalToUserID + '" and meta_value=' + userId + ')';
}
sql += ' ORDER BY message_id;';
msgDb.each(sql, function msgRow(err, row) {
if(!err) {
msgList.push( {
messageId : row.message_id,
messageUuid : row.message_uuid,
replyToMsgId : row.reply_to_message_id,
toUserName : row.to_user_name,
fromUserName : row.from_user_name,
subject : row.subject,
modTimestamp : row.modified_timestamp,
viewCount : row.view_count,
} );
}
}, callback);
}
],
function complete(err) {
console.log(msgList)
cb(err, msgList);
}
);
}
function getMessageListForArea(options, areaName, cb) {
//
// options.client (required)

104
core/new_scan.js Normal file
View File

@ -0,0 +1,104 @@
/* jslint node: true */
'use strict';
// ENiGMA½
var msgArea = require('./message_area.js');
var Message = require('./message.js');
var MenuModule = require('./menu_module.js').MenuModule;
var async = require('async');
exports.moduleInfo = {
name : 'New Scan',
desc : 'Performs a new scan against various areas of the system',
author : 'NuSkooler',
};
exports.getModule = NewScanModule;
/*
* :TODO:
* * Update message ID when reading (this should be working!)
* * New scan all areas
* * User configurable new scan: Area selection (avail from messages area)
*
*
*/
function NewScanModule(options) {
MenuModule.call(this, options);
var self = this;
var config = this.menuConfig.config;
this.currentStep = 'privateMail';
this.newScanMessageArea = function(areaName, cb) {
async.waterfall(
[
function newScanAreaAndGetMessages(callback) {
msgArea.getNewMessagesInAreaForUser(
self.client.user.userId, areaName, function msgs(err, msgList) {
callback(err, msgList);
}
);
},
function displayMessageList(msgList, callback) {
if(msgList && msgList.length > 0) {
var nextModuleOpts = {
extraArgs: {
messageAreaName : areaName,
messageList : msgList,
}
};
self.gotoMenu(config.newScanMessageList || 'newScanMessageList', nextModuleOpts);
} else {
callback(null);
}
}
],
function complete(err) {
cb(err);
}
);
};
}
require('util').inherits(NewScanModule, MenuModule);
NewScanModule.prototype.getSaveState = function() {
return {
currentStep : this.currentStep,
};
};
NewScanModule.prototype.restoreSavedState = function(savedState) {
this.currentStep = savedState.currentStep;
};
NewScanModule.prototype.mciReady = function(mciData, cb) {
var self = this;
// :TODO: display scan step/etc.
switch(this.currentStep) {
case 'privateMail' :
self.currentStep = 'finished';
self.newScanMessageArea(Message.WellKnownAreaNames.Private, cb);
break;
default :
cb(null);
}
};
/*
NewScanModule.prototype.finishedLoading = function() {
NewScanModule.super_.prototype.finishedLoading.call(this);
};
*/

View File

@ -109,7 +109,7 @@ function getPredefinedMCIValue(client, code) {
TC : function totalCalls() { return sysProp.getSystemProperty('login_count').toString(); },
}[code]();
}[code](); // :TODO: Just call toString() here and remove above - DRY
} catch(e) {
// Don't use client.log here as we may not have a client logger established yet!!

View File

@ -2,7 +2,7 @@
'use strict';
var theme = require('./theme.js');
var clientConnections = require('./client_connections.js').clientConnections;
var removeClient = require('./client_connections.js').removeClient;
var ansi = require('./ansi_term.js');
var userDb = require('./database.js').dbs.user;
var sysProp = require('./system_property.js');
@ -50,9 +50,11 @@ function logoff(callingMenu, formData, extraArgs) {
client.term.write(
ansi.normal() + '\n' +
iconv.decode(require('crypto').randomBytes(Math.floor(Math.random() * 65) + 20), client.term.outputEncoding) +
'NO CARRIER');
'NO CARRIER', null, function written() {
client.end();
// after data is written, disconnect & remove the client
removeClient(client);
});
}, 500);
}

View File

@ -5,6 +5,7 @@ var theme = require('./theme.js');
var clientConnections = require('./client_connections.js').clientConnections;
var userDb = require('./database.js').dbs.user;
var sysProp = require('./system_property.js');
var logger = require('./logger.js');
var async = require('async');
var _ = require('lodash');
@ -48,13 +49,13 @@ function userLogin(client, username, password, cb) {
var existingConnError = new Error('Already logged in as supplied user');
existingClientConnection.existingConn = true;
cb(existingClientConnection);
return;
return cb(existingClientConnection);
}
// use client.user so we can get correct case
client.log.info( { username : user.username }, 'Successful login');
// 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');
async.parallel(
[

View File

@ -73,7 +73,33 @@ WhosOnlineModule.prototype.mciReady = function(mciData, cb) {
var now = moment();
onlineListView.setItems(_.map(onlineList, function formatOnlineEntry(oe) {
onlineListView.setItems(_.map(onlineList, function formatOnlineEntry(oe) {
var fmtObj = {
node : oe.node,
userId : oe.user.userId,
userName : oe.user.username,
realName : oe.user.properties.real_name,
timeOn : function getTimeOn() {
var diff = now.diff(moment(oe.user.properties.last_login_timestamp), 'minutes');
return _.capitalize(moment.duration(diff, 'minutes').humanize());
},
action : function getCurrentAction() {
var cmm = oe.currentMenuModule;
if(cmm) {
return cmm.menuConfig.desc || 'Unknown';
}
return 'Unknown';
//oe.currentMenuModule.menuConfig.desc || 'Unknown',
},
location : oe.user.properties.location,
affils : oe.user.properties.affiliation,
};
try {
return listFormat.format(fmtObj);
} catch(e) {
console.log('Exception caught formatting: ' + e.toString() + ':\n' + JSON.stringify(fmtObj));
}
/*
return listFormat.format({
node : oe.node,
userId : oe.user.userId,
@ -94,6 +120,7 @@ WhosOnlineModule.prototype.mciReady = function(mciData, cb) {
location : oe.user.properties.location,
affils : oe.user.properties.affiliation,
});
*/
}));
// :TODO: This is a hack until pipe codes are better implemented