diff --git a/core/ftn_mail_packet.js b/core/ftn_mail_packet.js index 5f4aeac1..c8312eeb 100644 --- a/core/ftn_mail_packet.js +++ b/core/ftn_mail_packet.js @@ -11,10 +11,8 @@ let _ = require('lodash'); let assert = require('assert'); let binary = require('binary'); let fs = require('fs'); -let util = require('util'); let async = require('async'); let iconv = require('iconv-lite'); -let buffers = require('buffers'); let moment = require('moment'); exports.Packet = Packet; @@ -835,8 +833,11 @@ function Packet() { // Message attributes defined in FTS-0001.016 // http://ftsc.org/docs/fts-0001.016 // +// See also: +// * http://www.skepticfiles.org/aj/basics03.htm +// Packet.Attribute = { - Private : 0x0001, + Private : 0x0001, // Private message / NetMail Crash : 0x0002, Received : 0x0004, Sent : 0x0008, @@ -844,7 +845,7 @@ Packet.Attribute = { InTransit : 0x0020, Orphan : 0x0040, KillSent : 0x0080, - Local : 0x0100, + Local : 0x0100, // Message is from *this* system Hold : 0x0200, Reserved0 : 0x0400, FileRequest : 0x0800, @@ -886,10 +887,6 @@ Packet.prototype.writeHeader = function(ws, packetHeader) { return this.writePacketHeader(packetHeader, ws); }; -Packet.prototype.writeMessage = function(ws, message, options) { - -} - Packet.prototype.writeMessageEntry = function(ws, msgEntry) { ws.write(msgEntry); return msgEntry.length; @@ -918,7 +915,7 @@ Packet.prototype.writeStream = function(ws, messages, options) { if(true === options.terminatePacket) { ws.write(new Buffer( [ 0 ] )); // final extra null term } -} +}; Packet.prototype.write = function(path, packetHeader, messages, options) { if(!_.isArray(messages)) { diff --git a/core/ftn_util.js b/core/ftn_util.js index 595ffca7..fdc5e5a6 100644 --- a/core/ftn_util.js +++ b/core/ftn_util.js @@ -8,12 +8,8 @@ let createNamedUUID = require('./uuid_util.js').createNamedUUID; let _ = require('lodash'); let assert = require('assert'); -let binary = require('binary'); -let fs = require('fs'); -let util = require('util'); let iconv = require('iconv-lite'); let moment = require('moment'); -let createHash = require('crypto').createHash; let uuid = require('node-uuid'); let os = require('os'); @@ -49,9 +45,6 @@ exports.getQuotePrefix = getQuotePrefix; // const ENIGMA_FTN_MSGID_NAMESPACE = uuid.parse('a5c7ae11-420c-4469-a116-0e9a6d8d2654'); -// Up to 5D FTN address RegExp -const ENIGMA_FTN_ADDRESS_REGEXP = /^([0-9]+:)?([0-9]+)(\/[0-9]+)?(\.[0-9]+)?(@[a-z0-9\-\.]+)?$/i; - // See list here: https://github.com/Mithgol/node-fidonet-jam function stringToNullPaddedBuffer(s, bufLen) { @@ -145,8 +138,6 @@ function getMessageSerialNumber(messageId) { const msSinceEnigmaEpoc = (Date.now() - Date.UTC(2016, 1, 1)); const hash = Math.abs(new FNV1a(msSinceEnigmaEpoc + messageId).value).toString(16); return `00000000${hash}`.substr(-8); - // return ('00000000' + ((Math.floor((Date.now() - Date.UTC(2016, 1, 1)) / 1000) + - // message.messageId)).toString(16)).substr(-8); } // @@ -207,16 +198,6 @@ function getProductIdentifier() { return `ENiGMA1/2 ${version} (${os.platform()}; ${os.arch()}; ${nodeVer})`; } -// -// Return a FSC-0030.001 compliant (http://ftsc.org/docs/fsc-0030.001) MESSAGE-ID -// -// -// -// :TODO: not implemented to spec at all yet :) -function getFTNMessageID(messageId, areaId) { - return messageId + '.' + areaId + '@' + getFTNAddress() + ' ' + getMessageSerialNumber(messageId) -} - // // Return a FRL-1004 style time zone offset for a // 'TZUTC' kludge line @@ -294,20 +275,20 @@ function getAbbreviatedNetNodeList(netNodes) { // Parse an abbreviated net/node list commonly used for SEEN-BY and PATH // function parseAbbreviatedNetNodeList(netNodes) { - const re = /([0-9]+)\/([0-9]+)\s?|([0-9]+)\s?/g; - let net; - let m; - let results = []; - while(null !== (m = re.exec(netNodes))) { - if(m[1] && m[2]) { - net = parseInt(m[1]); - results.push(new Address( { net : net, node : parseInt(m[2]) } )); - } else if(net) { - results.push(new Address( { net : net, node : parseInt(m[3]) } )); - } - } - - return results; + const re = /([0-9]+)\/([0-9]+)\s?|([0-9]+)\s?/g; + let net; + let m; + let results = []; + while(null !== (m = re.exec(netNodes))) { + if(m[1] && m[2]) { + net = parseInt(m[1]); + results.push(new Address( { net : net, node : parseInt(m[2]) } )); + } else if(net) { + results.push(new Address( { net : net, node : parseInt(m[3]) } )); + } + } + + return results; } // diff --git a/core/scanner_tossers/ftn_bso.js b/core/scanner_tossers/ftn_bso.js index 8a83526c..d4118e9a 100644 --- a/core/scanner_tossers/ftn_bso.js +++ b/core/scanner_tossers/ftn_bso.js @@ -184,7 +184,7 @@ function FTNMessageScanTossModule() { let fileName = `${basename}.${moment().format('dd').toLowerCase()}`; async.detectSeries(EXT_SUFFIXES, (suffix, callback) => { const checkFileName = fileName + suffix; - fs.stat(paths.join(basePath, checkFileName), (err, stats) => { + fs.stat(paths.join(basePath, checkFileName), err => { callback((err && 'ENOENT' === err.code) ? true : false); }); }, finalSuffix => { @@ -213,7 +213,8 @@ function FTNMessageScanTossModule() { message.meta.FtnProperty.ftn_tear_line = ftnUtil.getTearLine(); // :TODO: Need an explicit isNetMail() check - let ftnAttribute = 0; + let ftnAttribute = + ftnMailPacket.Packet.Attribute.Local; // message from our system if(message.isPrivate()) { ftnAttribute |= ftnMailPacket.Packet.Attribute.Private; @@ -230,7 +231,7 @@ function FTNMessageScanTossModule() { } else { // // EchoMail requires some additional properties & kludges - // + // message.meta.FtnProperty.ftn_origin = ftnUtil.getOrigin(options.network.localAddress); message.meta.FtnProperty.ftn_area = Config.messageNetworks.ftn.areas[message.areaTag].tag; @@ -586,6 +587,10 @@ function FTNMessageScanTossModule() { exportOpts.nodeConfig.archiveType, tempBundlePath, exportedFileNames, err => { + if(err) { + return callback(err); + } + // :TODO: we need to delete the original input file(s) fs.rename(tempBundlePath, bundlePath, err => { callback(err, [ bundlePath ] ); @@ -614,10 +619,13 @@ function FTNMessageScanTossModule() { Log.trace( Object.assign(stats, { tempDir : exportOpts.tempDir }), 'Temporary directory cleaned up'); + + callback(null); }); } ], err => { + // :TODO: do something with |err| ? nextUplink(); } ); @@ -648,16 +656,8 @@ function FTNMessageScanTossModule() { this.importNetMailToArea = function(localAreaTag, header, message, cb) { async.series( [ - function validateDestinationAddress(callback) { - /* - const messageDestAddress = new Address({ - node : message.meta.FtnProperty.ftn_dest_node, - net : message.meta.FtnProperty.ftn_dest_network, - }); - */ - - const localNetworkPattern = `${message.meta.FtnProperty.ftn_dest_network}/${message.meta.FtnProperty.ftn_dest_node}`; - + function validateDestinationAddress(callback) { + const localNetworkPattern = `${message.meta.FtnProperty.ftn_dest_network}/${message.meta.FtnProperty.ftn_dest_node}`; const localNetworkName = self.getNetworkNameByAddressPattern(localNetworkPattern); callback(_.isString(localNetworkName) ? null : new Error('Packet destination is not us')); @@ -698,7 +698,8 @@ function FTNMessageScanTossModule() { callback(err); }); } - ], err => { + ], + err => { cb(err); } ); @@ -1002,10 +1003,18 @@ FTNMessageScanTossModule.prototype.performExport = function(cb) { return cb(new Error('Missing or invalid configuration')); } + // + // Select all messages that have a message_id > our last scan ID. + // Additionally exclude messages that have a ftn_attr_flags FtnProperty meta + // as those came via import! + // const getNewUuidsSql = `SELECT message_id, message_uuid - FROM message - WHERE area_tag = ? AND message_id > ? + FROM message m + WHERE area_tag = ? AND message_id > ? AND + (SELECT COUNT(message_id) + FROM message_meta + WHERE message_id = m.message_id AND meta_category = 'FtnProperty' AND meta_name = 'ftn_attr_flags') = 0 ORDER BY message_id;`; var self = this;