From 11a19d899e99e4f46a1732b436a788000b11c13f Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Sun, 31 Dec 2017 18:45:39 -0700 Subject: [PATCH] * Use per-network outbound for NetMail just like EchoMail * Use BSO style FLO file for NetMail * Some code cleanup --- core/config.js | 87 ++++++++++++++++----------------- core/scanner_tossers/ftn_bso.js | 25 ++++++++-- 2 files changed, 62 insertions(+), 50 deletions(-) diff --git a/core/config.js b/core/config.js index 34be676e..f9f277a8 100644 --- a/core/config.js +++ b/core/config.js @@ -2,7 +2,6 @@ 'use strict'; // ENiGMA½ -const miscUtil = require('./misc_util.js'); // deps const fs = require('graceful-fs'); @@ -32,7 +31,7 @@ function hasMessageConferenceAndArea(config) { _.forEach(nonInternalConfs, confTag => { if(_.has(config.messageConferences[confTag], 'areas') && Object.keys(config.messageConferences[confTag].areas) > 0) - { + { result = true; return false; // stop iteration } @@ -67,12 +66,12 @@ function init(configPath, options, cb) { } return callback(null, configJson); - }); + }); }, function mergeWithDefaultConfig(configJson, callback) { const mergedConfig = _.mergeWith( - getDefaultConfig(), + getDefaultConfig(), configJson, (conf1, conf2) => { // Arrays should always concat if(_.isArray(conf1)) { @@ -147,15 +146,13 @@ function getDefaultConfig() { webMax : 255, requireActivation : false, // require SysOp activation? false = auto-activate - invalidUsernames : [], groups : [ 'users', 'sysops' ], // built in groups defaultGroups : [ 'users' ], // default groups new users belong to newUserNames : [ 'new', 'apply' ], // Names reserved for applying - // :TODO: Mystic uses TRASHCAN.DAT for this -- is there a reason to support something like that? - badUserNames : [ + badUserNames : [ 'sysop', 'admin', 'administrator', 'root', 'all', 'areamgr', 'filemgr', 'filefix', 'areafix', 'allfix' ], @@ -187,7 +184,7 @@ function getDefaultConfig() { menus : { cls : true, // Clear screen before each menu by default? - }, + }, paths : { config : paths.join(__dirname, './../config/'), @@ -202,11 +199,11 @@ function getDefaultConfig() { themes : paths.join(__dirname, './../art/themes/'), logs : paths.join(__dirname, './../logs/'), // :TODO: set up based on system, e.g. /var/logs/enigmabbs or such db : paths.join(__dirname, './../db/'), - modsDb : paths.join(__dirname, './../db/mods/'), + modsDb : paths.join(__dirname, './../db/mods/'), dropFiles : paths.join(__dirname, './../dropfiles/'), // + "/node/ misc : paths.join(__dirname, './../misc/'), }, - + loginServers : { telnet : { port : 8888, @@ -219,7 +216,7 @@ function getDefaultConfig() { // // Private key in PEM format - // + // // Generating your PK: // > openssl genrsa -des3 -out ./config/ssh_private_key.pem 2048 // @@ -248,7 +245,7 @@ function getDefaultConfig() { resetPassword : { // // The following templates have these variables available to them: - // + // // * %BOARDNAME% : Name of BBS // * %USERNAME% : Username of whom to reset password // * %TOKEN% : Reset token @@ -263,10 +260,10 @@ function getDefaultConfig() { // resetPageTemplate : paths.join(__dirname, './../www/reset_password.template.html'), }, - + http : { enabled : false, - port : 8080, + port : 8080, }, https : { enabled : false, @@ -283,10 +280,10 @@ function getDefaultConfig() { }, Exiftool : { cmd : 'exiftool', - args : [ + args : [ '-charset', 'utf8', '{filePath}', // exclude the following: - '--directory', '--filepermissions', '--exiftoolversion', '--filename', '--filesize', + '--directory', '--filepermissions', '--exiftoolversion', '--filename', '--filesize', '--filemodifydate', '--fileaccessdate', '--fileinodechangedate', '--createdate', '--modifydate', '--metadatadate', '--xmptoolkit' ] @@ -305,7 +302,7 @@ function getDefaultConfig() { // // // :TODO: text/x-ansi -> SAUCE extraction for .ans uploads - // :TODO: textual : bool -- if text, we can view. + // :TODO: textual : bool -- if text, we can view. // :TODO: asText : { cmd, args[] } -> viewable text // @@ -388,7 +385,7 @@ function getDefaultConfig() { sig : '526172211a0700', offset : 0, archiveHandler : 'Rar', - }, + }, 'application/gzip' : { desc : 'Gzip Archive', sig : '1f8b', @@ -400,28 +397,28 @@ function getDefaultConfig() { desc : 'BZip2 Archive', sig : '425a68', offset : 0, - archiveHandler : '7Zip', + archiveHandler : '7Zip', }, 'application/x-lzh-compressed' : { desc : 'LHArc Archive', sig : '2d6c68', offset : 2, - archiveHandler : 'Lha', + archiveHandler : 'Lha', }, 'application/x-7z-compressed' : { desc : '7-Zip Archive', sig : '377abcaf271c', offset : 0, - archiveHandler : '7Zip', + archiveHandler : '7Zip', } // :TODO: update archives::formats to fall here // * archive handler -> archiveHandler (consider archive if archiveHandler present) // * sig, offset, ... // * mime-db -> exts lookup - // * + // * }, - + archives : { archivers : { '7Zip' : { @@ -514,7 +511,7 @@ function getDefaultConfig() { list : { cmd : 'tar', args : [ '-tvf', '{archivePath}' ], - entryMatch : '^[drwx\\-]{10}\\s[A-Za-z0-9\\/]+\\s+([0-9]+)\\s[0-9]{4}\\-[0-9]{2}\\-[0-9]{2}\\s[0-9]{2}\\:[0-9]{2}\\s([^\\r\\n]+)$', + entryMatch : '^[drwx\\-]{10}\\s[A-Za-z0-9\\/]+\\s+([0-9]+)\\s[0-9]{4}\\-[0-9]{2}\\-[0-9]{2}\\s[0-9]{2}\\:[0-9]{2}\\s([^\\r\\n]+)$', }, extract : { cmd : 'tar', @@ -523,7 +520,7 @@ function getDefaultConfig() { } }, }, - + fileTransferProtocols : { // // See http://www.synchro.net/docs/sexyz.txt for information on SEXYZ @@ -539,7 +536,7 @@ function getDefaultConfig() { recvCmd : 'sexyz', recvArgs : [ '-telnet', '-8', 'rz', '{uploadDir}' ], recvArgsNonBatch : [ '-telnet', '-8', 'rz', '{fileName}' ], - } + } }, xmodemSexyz : { @@ -570,7 +567,7 @@ function getDefaultConfig() { name : 'ZModem 8k', type : 'external', sort : 2, - external : { + external : { sendCmd : 'sz', // Avail on Debian/Ubuntu based systems as the package "lrzsz" sendArgs : [ // :TODO: try -q @@ -581,11 +578,11 @@ function getDefaultConfig() { '--zmodem', '--binary', '--restricted', '--keep-uppercase', // dumps to CWD which is set to {uploadDir} ], // :TODO: can we not just use --escape ? - escapeTelnet : true, // set to true to escape Telnet codes such as IAC - } + escapeTelnet : true, // set to true to escape Telnet codes such as IAC + } } }, - + messageAreaDefaults : { // // The following can be override per-area as well @@ -594,11 +591,11 @@ function getDefaultConfig() { maxAgeDays : 0, // 0 = unlimited }, - messageConferences : { + messageConferences : { system_internal : { name : 'System Internal', desc : 'Built in conference for private messages, bulletins, etc.', - + areas : { private_mail : { name : 'Private Mail', @@ -612,7 +609,7 @@ function getDefaultConfig() { } } }, - + scannerTossers : { ftn_bso : { paths : { @@ -620,7 +617,7 @@ function getDefaultConfig() { inbound : paths.join(__dirname, './../mail/ftn_in/'), secInbound : paths.join(__dirname, './../mail/ftn_secin/'), reject : paths.join(__dirname, './../mail/reject/'), // bad pkt, bundles, TIC attachments that fail any check, etc. - outboundNetMail : paths.join(__dirname, './../mail/ftn_netmail_out/'), + //outboundNetMail : paths.join(__dirname, './../mail/ftn_netmail_out/'), // set 'retain' to a valid path to keep good pkt files }, @@ -644,7 +641,7 @@ function getDefaultConfig() { }, fileBase: { - // areas with an explicit |storageDir| will be stored relative to |areaStoragePrefix|: + // areas with an explicit |storageDir| will be stored relative to |areaStoragePrefix|: areaStoragePrefix : paths.join(__dirname, './../file_base/'), maxDescFileByteSize : 471859, // ~1/4 MB @@ -654,12 +651,12 @@ function getDefaultConfig() { // These are NOT case sensitive // FILE_ID.DIZ - https://en.wikipedia.org/wiki/FILE_ID.DIZ // Some groups include a FILE_ID.ANS. We try to use that over FILE_ID.DIZ if available. - desc : [ + desc : [ '^[^/\]*FILE_ID\.ANS$', '^[^/\]*FILE_ID\.DIZ$', '^[^/\]*DESC\.SDI$', '^[^/\]*DESCRIPT\.ION$', '^[^/\]*FILE\.DES$', '^[^/\]*FILE\.SDI$', '^[^/\]*DISK\.ID$' ], // common README filename - https://en.wikipedia.org/wiki/README - descLong : [ + descLong : [ '^[^/\]*\.NFO$', '^[^/\]*README\.1ST$', '^[^/\]*README\.NOW$', '^[^/\]*README\.TXT$', '^[^/\]*READ\.ME$', '^[^/\]*README$', '^[^/\]*README\.md$' ], }, @@ -675,7 +672,7 @@ function getDefaultConfig() { '\\b[0-3]?[0-9][\\-\\/\\.][0-3]?[0-9][\\-\\/\\.]((?:[1789][0-9]))\\b', // mm-dd-yy, mm/dd/yy, ... //'\\b((?:[1-2][0-9][0-9]{2}))[\\-\\/\\.][0-3]?[0-9][\\-\\/\\.][0-3]?[0-9]|[0-3]?[0-9][\\-\\/\\.][0-3]?[0-9][\\-\\/\\.]((?:[0-9]{2})?[0-9]{2})\\b', // yyyy-mm-dd, m/d/yyyy, mm-dd-yyyy, etc. //"\\b('[1789][0-9])\\b", // eslint-disable-line quotes - '\\b[0-3]?[0-9][\\-\\/\\.](?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|january|february|march|april|may|june|july|august|september|october|november|december)[\\-\\/\\.]((?:[0-9]{2})?[0-9]{2})\\b', + '\\b[0-3]?[0-9][\\-\\/\\.](?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|january|february|march|april|may|june|july|august|september|october|november|december)[\\-\\/\\.]((?:[0-9]{2})?[0-9]{2})\\b', '\\b(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|january|february|march|april|may|june|july|august|september|october|november|december),?\\s[0-9]+(?:st|nd|rd|th)?,?\\s((?:[0-9]{2})?[0-9]{2})\\b', // November 29th, 1997 '\\(((?:19|20)[0-9]{2})\\)', // (19xx) or (20xx) -- with parens -- do this before 19xx 20xx such that this has priority '\\b((?:19|20)[0-9]{2})\\b', // simple 19xx or 20xx with word boundaries @@ -692,7 +689,7 @@ function getDefaultConfig() { // // File area storage location tag/value pairs. // Non-absolute paths are relative to |areaStoragePrefix|. - // + // storageTags : { sys_msg_attach : 'sys_msg_attach', sys_temp_download : 'sys_temp_download', @@ -712,20 +709,20 @@ function getDefaultConfig() { } } }, - + eventScheduler : { - + events : { trimMessageAreas : { // may optionally use [or ]@watch:/path/to/file schedule : 'every 24 hours', - + // action: // - @method:path/to/module.js:theMethodName // (path is relative to engima base dir) // - // - @execute:/path/to/something/executable.sh - // + // - @execute:/path/to/something/executable.sh + // action : '@method:core/message_area.js:trimMessageAreasScheduledEvent', }, @@ -739,7 +736,7 @@ function getDefaultConfig() { action : '@method:core/web_password_reset.js:performMaintenanceTask', args : [ '24 hours' ] // items older than this will be removed } - } + } }, misc : { diff --git a/core/scanner_tossers/ftn_bso.js b/core/scanner_tossers/ftn_bso.js index 996dd3ef..ac6ead52 100644 --- a/core/scanner_tossers/ftn_bso.js +++ b/core/scanner_tossers/ftn_bso.js @@ -893,6 +893,8 @@ function FTNMessageScanTossModule() { exportOpts.fileCase = config.fileCase || 'lower'; exportOpts.network = Config.messageNetworks.ftn.networks[networkName]; exportOpts.networkName = networkName; + exportOpts.outgoingDir = self.getOutgoingEchoMailPacketDir(exportOpts.networkName, exportOpts.destAddress); + exportOpts.exportType = self.getExportType(config); if(!exportOpts.network) { return callback(Errors.DoesNotExist(`No configuration found for network ${networkName}`)); @@ -902,20 +904,33 @@ function FTNMessageScanTossModule() { }); }, function createOutgoingDir(callback) { - // ensure outgoing NetMail directory exists - return fse.mkdirs(Config.scannerTossers.ftn_bso.paths.outboundNetMail, callback); + // ensure outgoing NetMail directory exists + return fse.mkdirs(exportOpts.outgoingDir, callback); + //return fse.mkdirs(Config.scannerTossers.ftn_bso.paths.outboundNetMail, callback); }, function exportPacket(callback) { return self.exportNetMailMessagePacket(message, exportOpts, callback); }, function moveToOutgoing(callback) { const newExt = exportOpts.fileCase === 'lower' ? '.pkt' : '.PKT'; - const newPath = paths.join( - Config.scannerTossers.ftn_bso.paths.outboundNetMail, + exportOpts.exportedToPath = paths.join( + exportOpts.outgoingDir, + //Config.scannerTossers.ftn_bso.paths.outboundNetMail, `${paths.basename(exportOpts.pktFileName, paths.extname(exportOpts.pktFileName))}${newExt}` ); - return fse.move(exportOpts.pktFileName, newPath, callback); + return fse.move(exportOpts.pktFileName, exportOpts.exportedToPath, callback); + }, + function prepareFloFile(callback) { + const flowFilePath = self.getOutgoingFlowFileName( + exportOpts.outgoingDir, + exportOpts.destAddress, + 'ref', + exportOpts.exportType, + exportOpts.fileCase + ); + + return self.flowFileAppendRefs(flowFilePath, [ exportOpts.exportedToPath ], '^', callback); }, function storeStateFlags0Meta(callback) { return message.persistMetaValue('System', 'state_flags0', Message.StateFlags0.Exported.toString(), callback);