diff --git a/core/fse.js b/core/fse.js index 1b5526fc..24d0c336 100644 --- a/core/fse.js +++ b/core/fse.js @@ -9,6 +9,7 @@ var MultiLineEditTextView = require('../core/multi_line_edit_text_view.js').Mul var Message = require('../core/message.js'); var getMessageAreaByName = require('../core/message_area.js').getMessageAreaByName; var updateMessageAreaLastReadId = require('../core/message_area.js').updateMessageAreaLastReadId; +var getUserIdAndName = require('../core/user.js').getUserIdAndName; var async = require('async'); var assert = require('assert'); @@ -67,7 +68,6 @@ var MCICodeIds = { To : 2, Subject : 3, AreaName : 4, - DateTime : 5, MsgNum : 6, MsgTotal : 7, @@ -103,20 +103,40 @@ function FullScreenEditorModule(options) { // editorType : email | area // editorMode : view | edit | quote // - // extraArgs - view mode + // menuConfig.config or extraArgs // messageAreaName // messageIndex / messageTotal + // toUserId // - // - this.editorType = config.editorType; - this.editorMode = config.editorMode; - - if(_.isObject(options.extraArgs)) { - //console.log(options.extraArgs) - this.messageAreaName = options.extraArgs.messageAreaName || Message.WellKnownAreaNames.Private; - this.messageIndex = options.extraArgs.messageIndex || 0; - this.messageTotal = options.extraArgs.messageTotal || 0; + this.editorType = config.editorType; + this.editorMode = config.editorMode; + + if(config.messageAreaName) { + this.messageAreaName = config.messageAreaName; } + + this.messageIndex = config.messageIndex || 0; + this.messageTotal = config.messageTotal || 0; + this.toUserId = config.toUserId || 0; + + // extraArgs can override some config + if(_.isObject(options.extraArgs)) { + if(options.extraArgs.messageAreaName) { + this.messageAreaName = options.extraArgs.messageAreaName; + } + if(options.extraArgs.messageIndex) { + this.messageIndex = options.extraArgs.messageIndex; + } + if(options.extraArgs.messageTotal) { + this.messageTotal = options.extraArgs.messageTotal; + } + if(options.extraArgs.toUserId) { + this.toUserId = options.extraArgs.toUserId; + } + } + + console.log(this.toUserId) + console.log(this.messageAreaName) this.isReady = false; @@ -129,7 +149,7 @@ function FullScreenEditorModule(options) { }; this.isLocalEmail = function() { - return 'email' === self.editorType && Message.WellKnownAreaNames.Private === self.messageAreaName; + return Message.WellKnownAreaNames.Private === self.messageAreaName; }; this.isReply = function() { @@ -214,21 +234,21 @@ function FullScreenEditorModule(options) { this.setMessage = function(message) { self.message = message; - if(!self.message.isPrivate()) { - updateMessageAreaLastReadId(self.client.user.userId, self.messageAreaName, self.message.messageId); - } + updateMessageAreaLastReadId( + self.client.user.userId, self.messageAreaName, self.message.messageId, + function lastReadUpdated() { - if(self.isReady) { - self.initHeaderViewMode(); - self.initFooterViewMode(); + if(self.isReady) { + self.initHeaderViewMode(); + self.initFooterViewMode(); - var bodyMessageView = self.viewControllers.body.getView(1); - if(bodyMessageView && _.has(self, 'message.message')) { - bodyMessageView.setText(self.message.message); - //bodyMessageView.redraw(); + var bodyMessageView = self.viewControllers.body.getView(1); + if(bodyMessageView && _.has(self, 'message.message')) { + bodyMessageView.setText(self.message.message); + //bodyMessageView.redraw(); + } } - } - + }); }; this.getMessage = function(cb) { @@ -242,12 +262,25 @@ function FullScreenEditorModule(options) { }, function populateLocalUserInfo(callback) { if(self.isLocalEmail()) { - msg.setLocalFromUserId(self.client.user.userId); - msg.setLocalToUserId(self.toUserId); + self.message.setLocalFromUserId(self.client.user.userId); + + if(self.toUserId > 0) { + self.message.setLocalToUserId(self.toUserId); + callback(null); + } else { + // we need to look it up + getUserIdAndName(self.message.toUserName, function userInfo(err, toUserId) { + if(err) { + callback(err); + } else { + self.message.setLocalToUserId(toUserId); + callback(null); + } + }); + } + } else { + callback(null); } - - // :TODO: DO THAT! - callback(null); } ], function complete(err) { diff --git a/core/message_area.js b/core/message_area.js index 61cbb786..53aec52b 100644 --- a/core/message_area.js +++ b/core/message_area.js @@ -4,6 +4,7 @@ var msgDb = require('./database.js').dbs.message; var Config = require('./config.js').config; var Message = require('./message.js'); +var Log = require('./logger.js').log; var async = require('async'); var _ = require('lodash'); @@ -105,6 +106,19 @@ function changeMessageArea(client, areaName, cb) { ); } +function getMessageFromRow(row) { + return { + 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, + }; +} + function getNewMessagesInAreaForUser(userId, areaName, cb) { // // If |areaName| is Message.WellKnownAreaNames.Private, @@ -135,19 +149,12 @@ function getNewMessagesInAreaForUser(userId, areaName, cb) { } sql += ' ORDER BY message_id;'; + + console.log(sql) 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, - } ); + msgList.push(getMessageFromRow(row)); } }, callback); } @@ -191,16 +198,7 @@ function getMessageListForArea(options, areaName, cb) { [ areaName.toLowerCase() ], 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, - } ); + msgList.push(getMessageFromRow(row)); } }, callback @@ -222,11 +220,13 @@ function getMessageAreaLastReadId(userId, areaName, cb) { 'FROM user_message_area_last_read ' + 'WHERE user_id = ? AND area_name = ?;', [ userId, areaName ], - cb // (err, lastId) + function complete(err, row) { + cb(err, row ? row.message_id : 0); + } ); } -function updateMessageAreaLastReadId(userId, areaName, messageId) { +function updateMessageAreaLastReadId(userId, areaName, messageId, cb) { // :TODO: likely a better way to do this... async.waterfall( [ @@ -241,10 +241,25 @@ function updateMessageAreaLastReadId(userId, areaName, messageId) { msgDb.run( 'REPLACE INTO user_message_area_last_read (user_id, area_name, message_id) ' + 'VALUES (?, ?, ?);', - [ userId, areaName, messageId ] + [ userId, areaName, messageId ], + callback ); + } else { + callback(null); } } - ] + ], + function complete(err) { + if(err) { + Log.debug( + { error : err.toString(), userId : userId, areaName : areaName, messageId : messageId }, + 'Failed updating area last read ID'); + } else { + Log.trace( + { userId : userId, areaName : areaName, messageId : messageId }, + 'Area last read ID updated'); + } + cb(err); + } ); } diff --git a/core/new_scan.js b/core/new_scan.js index cc855b34..3201402a 100644 --- a/core/new_scan.js +++ b/core/new_scan.js @@ -19,14 +19,16 @@ 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) + * * User configurable new scan: Area selection (avail from messages area) (sep module) * * Add status TL/VM (either/both should update if present) * * */ +var MciCodeIds = { + ScanStatusLabel : 1, // TL1 + ScanStatusList : 2, // VM2 (appends) +}; function NewScanModule(options) { MenuModule.call(this, options); @@ -35,9 +37,27 @@ function NewScanModule(options) { var config = this.menuConfig.config; this.currentStep = 'messageAreas'; - this.currentScanAux = 0; // Message.WellKnownAreaNames.Private + this.currentScanAux = 0; // e.g. Message.WellKnownAreaNames.Private when currentSteps = messageAreas + + this.scanStartFmt = config.scanStartFmt || 'Scanning {desc}...'; + this.scanFinishNoneFmt = config.scanFinishNoneFmt || 'Nothing new'; + this.scanFinishNewFmt = config.scanFinishNewFmt || '{count} entries found'; + this.scanCompleteMsg = config.scanCompleteMsg || 'Finished newscan'; + + this.updateScanStatus = function(statusText) { + var vc = self.viewControllers.allViews; + + var view = vc.getView(MciCodeIds.ScanStatusLabel); + if(view) { + view.setText(statusText); + } + + view = vc.getView(MciCodeIds.ScanStatusList); + // :TODO: MenuView needs appendItem() + if(view) { + } + }; - this.newScanMessageArea = function(cb) { var availMsgAreas = msgArea.getAvailableMessageAreas( { includePrivate : true } ); var currentArea = availMsgAreas[self.currentScanAux]; @@ -54,16 +74,31 @@ function NewScanModule(options) { self.currentScanAux += 1; callback(null); } else { + self.updateScanStatus(self.scanCompleteMsg); callback(new Error('No more areas')); } }, - function updateStatus(callback) { - // :TODO: Update status text + function updateStatusScanStarted(callback) { + self.updateScanStatus(self.scanStartFmt.format({ + desc : currentArea.desc, + })); callback(null); }, function newScanAreaAndGetMessages(callback) { msgArea.getNewMessagesInAreaForUser( self.client.user.userId, currentArea.name, function msgs(err, msgList) { + if(!err) { + if(0 === msgList.length) { + self.updateScanStatus(self.scanFinishNoneFmt.format({ + desc : currentArea.desc, + })); + } else { + self.updateScanStatus(self.scanFinishNewFmt.format({ + desc : currentArea.desc, + count : msgList.length, + })); + } + } callback(err, msgList); } ); diff --git a/mods/menu.hjson b/mods/menu.hjson index c00d4716..7c710ce2 100644 --- a/mods/menu.hjson +++ b/mods/menu.hjson @@ -369,9 +369,6 @@ art: LETTER options: { pause: true } next: newUserFeedbackToSysOp - extraArgs: { - messageAreaName: private_mail - } } newUserFeedbackToSysOp: { @@ -395,7 +392,9 @@ help: MSGEHLP }, editorMode: edit - editorType: area + editorType: email + messageAreaName: private_mail + toUserId: 1 /* always to +op */ } form: { 0: { @@ -505,6 +504,7 @@ options: { pause: true } next: fullLoginSequenceLastCallers } + fullLoginSequenceLastCallers: { desc: Last Callers module: last_callers @@ -517,8 +517,34 @@ module: whos_online art: WHOSON options: { pause: true } - next: fullLoginSequenceSysStats + next: fullLoginSequenceNewScanConfirm } + + fullLoginSequenceNewScanConfirm: { + desc: Logging In + prompt: loginGlobalNewScan + submit: [ + { + value: { promptValue: 0 } + action: @menu:fullLoginSequenceNewScan + } + { + value: { promptValue: 1 } + action: @menu:fullLoginSequenceUserStats + } + ] + } + + fullLoginSequenceNewScan: { + desc: Performing New Scan + module: @systemModule:new_scan + art: NEWSCAN + next: fullLoginSequenceSysStats + config: { + messageListMenu: newScanMessageList + } + } + fullLoginSequenceSysStats: { desc: System Stats art: SYSSTAT @@ -532,6 +558,40 @@ next: mainMenu } + newScanMessageList: { + desc: Viewing New Message List + module: msg_list + art: NEWMSGS + config: { + menuViewPost: messageAreaViewPost + } + form: { + 0: { + mci: { + VM1: { + focus: true + submit: true + argName: message + } + } + submit: { + *: [ + { + value: { message: null } + action: @method:selectMessage + } + ] + } + actionKeys: [ + { + keys: [ "escape", "q", "shift + q" ] + action: @systemMethod:prevMenu + } + ] + } + } + } + /////////////////////////////////////////////////////////////////////// // Main Menu /////////////////////////////////////////////////////////////////////// @@ -743,6 +803,10 @@ value: { command: "4" } action: @menu:doorTradeWars2002BBSLink } + { + value: { command: "DL" } + action: @menu:doorDarkLands + } ] } @@ -763,6 +827,24 @@ io: socket } } + + doorDarkLands: { + desc: Playing Dark Lands + module: abracadabra + config: { + name: DARKLANDS + dropFileType: DOOR + cmd: /home/nuskooler/dev/enigma-bbs/doors/darklands/start.sh + args: [ + "{node}", + "{dropFile}", + "{srvPort}", + ], + nodeMax: 1 + tooManyArt: DOORMANY + io: socket + } + } doorLORD: { desc: Playing L.O.R.D. @@ -860,7 +942,6 @@ module: msg_list art: MSGLIST config: { - listType: public menuViewPost: messageAreaViewPost } form: { diff --git a/mods/msg_area_post_fse.js b/mods/msg_area_post_fse.js index f5439004..4723da68 100644 --- a/mods/msg_area_post_fse.js +++ b/mods/msg_area_post_fse.js @@ -45,7 +45,7 @@ function AreaPostFSEModule(options) { if(err) { // :TODO:... sooooo now what? } else { - console.log(msg); + console.log(msg); // :TODO: remove me -- probably log that one was saved, however. } self.nextMenu(); diff --git a/mods/msg_list.js b/mods/msg_list.js index 27bb9240..c5fbe768 100644 --- a/mods/msg_list.js +++ b/mods/msg_list.js @@ -52,9 +52,21 @@ function MessageListModule(options) { var self = this; var config = this.menuConfig.config; - this.listType = config.listType || 'public'; + this.messageAreaName = config.messageAreaName; - this.messageList = []; + if(options.extraArgs) { + // + // |extraArgs| can override |messageAreaName| provided by config + // as well as supply a pre-defined message list + // + if(options.extraArgs.messageAreaName) { + this.messageAreaName = options.extraArgs.messageAreaName; + } + + if(options.extraArgs.messageList) { + this.messageList = options.extraArgs.messageList; + } + } this.menuMethods = { selectMessage : function(formData, extraArgs) { @@ -85,9 +97,11 @@ require('util').inherits(MessageListModule, MenuModule); MessageListModule.prototype.enter = function(client) { MessageListModule.super_.prototype.enter.call(this, client); - if('private' === this.listType) { - this.messageAreaName = Message.WellKnownAreaNames.Private; - } else { + // + // Config can specify |messageAreaName| else it comes from + // the user's current area + // + if(!this.messageAreaName) { this.messageAreaName = client.user.properties.message_area_name; } }; @@ -110,14 +124,21 @@ MessageListModule.prototype.mciReady = function(mciData, cb) { vc.loadFromMenuConfig(loadOpts, callback); }, function fetchMessagesInArea(callback) { - messageArea.getMessageListForArea( { client : self.client }, self.messageAreaName, function msgs(err, msgList) { - if(msgList && 0 === msgList.length) { - callback(new Error('No messages in area')); - } else { - self.messageList = msgList; - callback(err); - } - }); + // + // Config can supply messages else we'll need to populate the list now + // + if(_.isArray(self.messageList)) { + callback(0 === self.messageList.length ? new Error('No messages in area') : null); + } else { + messageArea.getMessageListForArea( { client : self.client }, self.messageAreaName, function msgs(err, msgList) { + if(msgList && 0 === msgList.length) { + callback(new Error('No messages in area')); + } else { + self.messageList = msgList; + callback(err); + } + }); + } }, function getLastReadMesageId(callback) { messageArea.getMessageAreaLastReadId(self.client.user.userId, self.messageAreaName, function lastRead(err, lastReadId) { diff --git a/mods/prompt.hjson b/mods/prompt.hjson index b1168bc4..0d774bc5 100644 --- a/mods/prompt.hjson +++ b/mods/prompt.hjson @@ -46,6 +46,19 @@ } } + loginGlobalNewScan: { + art: GNSPMPT + mci: { + TM1: { + argName: promptValue + items: [ "yes", "no" ] + focus: true + hotKeys: { Y: 0, N: 1 } + hotKeySubmit: true + } + } + } + "menuCommand" : { art: MNUPRMT "mci" : { diff --git a/oputil.js b/oputil.js old mode 100644 new mode 100755 index c1aa2450..5eef5339 --- a/oputil.js +++ b/oputil.js @@ -1,3 +1,5 @@ +#!/usr/bin/env node + /* jslint node: true */ 'use strict'; @@ -85,7 +87,7 @@ function handleUserCommand() { function setNewPass(userId, callback) { assert(_.isNumber(userId)); assert(userId > 0); - + var u = new user.User(); u.userId = userId; @@ -114,6 +116,10 @@ function main() { process.exitCode = ExitCodes.SUCCESS; + if(true === argv.version) { + return console.info(require('./package.json').version); + } + if(0 === argv._.length || 'help' === argv._[0]) { diff --git a/package.json b/package.json index dc5ae3ab..aed5721b 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "telnet" ], "dependencies": { - "async": "^1.5.0", + "async": "^1.5.1", "binary": "0.3.x", "buffers": "0.1.x", "bunyan": "1.5.x", @@ -21,15 +21,16 @@ "hjson": "1.7.x", "iconv-lite": "^0.4.13", "lodash": "^3.10.1", + "minimist": "1.2.x", "mkdirp": "0.5.x", - "moment": "^2.10.6", + "moment": "^2.11.0", "node-uuid": "^1.4.7", - "ptyw.js": "^0.3.4", + "ptyw.js": "^0.3.7", "sqlite3": "^3.1.1", - "ssh2": "^0.4.12", + "ssh2": "^0.4.13", "string-format": "davidchambers/string-format#mini-language" }, - "engines" : { - "node" : ">=0.12.2" + "engines": { + "node": ">=0.12.2" } }