* New Address class for FTN addresses + experiment with ES6 classes
* Move a lot of address functionality/parsing/etc. to Address * WIP on ftn_bso scan/tosser * PATH and SEEN-BY creation, parsing, etc.
This commit is contained in:
parent
7b5ab029f9
commit
13d5c4d8f4
|
@ -0,0 +1,169 @@
|
||||||
|
/* jslint node: true */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let _ = require('lodash');
|
||||||
|
|
||||||
|
const FTN_ADDRESS_REGEXP = /^([0-9]+:)?([0-9]+)(\/[0-9]+)?(\.[0-9]+)?(@[a-z0-9\-\.]+)?$/i;
|
||||||
|
const FTN_PATTERN_REGEXP = /^([0-9\*]+:)?([0-9\*]+)(\/[0-9\*]+)?(\.[0-9\*]+)?(@[a-z0-9\-\.\*]+)?$/i;
|
||||||
|
|
||||||
|
module.exports = class Address {
|
||||||
|
constructor(addr) {
|
||||||
|
if(addr) {
|
||||||
|
if(_.isObject(addr)) {
|
||||||
|
Object.assign(this, addr);
|
||||||
|
} else if(_.isString(addr)) {
|
||||||
|
const temp = Address.fromString(addr);
|
||||||
|
if(temp) {
|
||||||
|
Object.assign(this, temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isEqual(other) {
|
||||||
|
if(_.isString(other)) {
|
||||||
|
other = Address.fromString(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
this.net === other.net &&
|
||||||
|
this.node === other.node &&
|
||||||
|
this.zone === other.zone &&
|
||||||
|
this.point === other.point &&
|
||||||
|
this.domain === other.domain
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
isMatch(pattern) {
|
||||||
|
const m = FTN_PATTERN_REGEXP.exec(pattern);
|
||||||
|
if(m) {
|
||||||
|
let addr = { };
|
||||||
|
|
||||||
|
if(m[1]) {
|
||||||
|
addr.zone = m[1].slice(0, -1)
|
||||||
|
if('*' !== addr.zone) {
|
||||||
|
addr.zone = parseInt(addr.zone);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addr.zone = '*';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m[2]) {
|
||||||
|
addr.net = m[2];
|
||||||
|
if('*' !== addr.net) {
|
||||||
|
addr.net = parseInt(addr.net);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addr.net = '*';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m[3]) {
|
||||||
|
addr.node = m[3].substr(1);
|
||||||
|
if('*' !== addr.node) {
|
||||||
|
addr.node = parseInt(addr.node);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addr.node = '*';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m[4]) {
|
||||||
|
addr.point = m[4].substr(1);
|
||||||
|
if('*' !== addr.point) {
|
||||||
|
addr.point = parseInt(addr.point);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addr.point = '*';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m[5]) {
|
||||||
|
addr.domain = m[5].substr(1);
|
||||||
|
} else {
|
||||||
|
addr.domain = '*';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
('*' === addr.net || this.net === addr.net) &&
|
||||||
|
('*' === addr.node || this.node === addr.node) &&
|
||||||
|
('*' === addr.zone || this.zone === addr.zone) &&
|
||||||
|
('*' === addr.point || this.point === addr.point) &&
|
||||||
|
('*' === addr.domain || this.domain === addr.domain)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromString(addrStr) {
|
||||||
|
const m = FTN_ADDRESS_REGEXP.exec(addrStr);
|
||||||
|
|
||||||
|
if(m) {
|
||||||
|
// start with a 2D
|
||||||
|
let addr = {
|
||||||
|
net : parseInt(m[2]),
|
||||||
|
node : parseInt(m[3].substr(1)),
|
||||||
|
};
|
||||||
|
|
||||||
|
// 3D: Addition of zone if present
|
||||||
|
if(m[1]) {
|
||||||
|
addr.zone = parseInt(m[1].slice(0, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4D if optional point is present
|
||||||
|
if(m[4]) {
|
||||||
|
addr.point = parseInt(m[4].substr(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5D with @domain
|
||||||
|
if(m[5]) {
|
||||||
|
addr.domain = m[5].substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Address(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(dimensions) {
|
||||||
|
dimensions = dimensions || '5D';
|
||||||
|
|
||||||
|
let addrStr = `${this.zone}:${this.net}`;
|
||||||
|
|
||||||
|
// allow for e.g. '4D' or 5
|
||||||
|
const dim = parseInt(dimensions.toString()[0]);
|
||||||
|
|
||||||
|
if(dim >= 3) {
|
||||||
|
addrStr += `/${this.node}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// missing & .0 are equiv for point
|
||||||
|
if(dim >= 4 && this.point) {
|
||||||
|
addrStr += `.${this.point}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(5 === dim && this.domain) {
|
||||||
|
addrStr += `@${this.domain.toLowerCase()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return addrStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getComparator() {
|
||||||
|
return function(left, right) {
|
||||||
|
let c = (left.zone || 0) - (right.zone || 0);
|
||||||
|
if(0 !== c) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = (left.net || 0) - (right.net || 0);
|
||||||
|
if(0 !== c) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = (left.node || 0) - (right.node || 0);
|
||||||
|
if(0 !== c) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (left.domain || '').localeCompare(right.domain || '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,19 +2,24 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
//var MailPacket = require('./mail_packet.js');
|
//var MailPacket = require('./mail_packet.js');
|
||||||
var ftn = require('./ftn_util.js');
|
let ftn = require('./ftn_util.js');
|
||||||
var Message = require('./message.js');
|
let Message = require('./message.js');
|
||||||
var sauce = require('./sauce.js');
|
let sauce = require('./sauce.js');
|
||||||
|
let Address = require('./ftn_address.js');
|
||||||
|
let strUtil = require('./string_util.js');
|
||||||
|
|
||||||
var _ = require('lodash');
|
let _ = require('lodash');
|
||||||
var assert = require('assert');
|
let assert = require('assert');
|
||||||
var binary = require('binary');
|
let binary = require('binary');
|
||||||
var fs = require('fs');
|
let fs = require('fs');
|
||||||
var util = require('util');
|
let util = require('util');
|
||||||
var async = require('async');
|
let async = require('async');
|
||||||
var iconv = require('iconv-lite');
|
let iconv = require('iconv-lite');
|
||||||
var buffers = require('buffers');
|
let buffers = require('buffers');
|
||||||
var moment = require('moment');
|
let moment = require('moment');
|
||||||
|
|
||||||
|
exports.PacketHeader = PacketHeader;
|
||||||
|
exports.Packet = Packet;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
:TODO: things
|
:TODO: things
|
||||||
|
@ -35,6 +40,88 @@ const FTN_MESSAGE_SAUCE_HEADER = new Buffer('SAUCE00');
|
||||||
|
|
||||||
const FTN_MESSAGE_KLUDGE_PREFIX = '\x01';
|
const FTN_MESSAGE_KLUDGE_PREFIX = '\x01';
|
||||||
|
|
||||||
|
function PacketHeader(options) {
|
||||||
|
}
|
||||||
|
|
||||||
|
PacketHeader.prototype.init = function(origAddr, destAddr, created, version) {
|
||||||
|
version = version || '2+';
|
||||||
|
|
||||||
|
const EMPTY_ADDRESS = {
|
||||||
|
node : 0,
|
||||||
|
net : 0,
|
||||||
|
zone : 0,
|
||||||
|
point : 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.packetVersion = version;
|
||||||
|
|
||||||
|
this.setOrigAddress(origAddr || EMPTY_ADDRESS);
|
||||||
|
this.setDestAddress(destAddr || EMPTY_ADDRESS);
|
||||||
|
this.setCreated(created || moment());
|
||||||
|
|
||||||
|
// uncommon to set the following explicitly
|
||||||
|
this.prodCodeLo = 0xfe; // http://ftsc.org/docs/fta-1005.003
|
||||||
|
this.prodRevLo = 0;
|
||||||
|
this.baud = 0;
|
||||||
|
this.packetType = FTN_PACKET_HEADER_TYPE;
|
||||||
|
this.password = '';
|
||||||
|
this.prodData = 0x47694e45; // "ENiG"
|
||||||
|
|
||||||
|
this.capWord = 0x0001;
|
||||||
|
this.capWordValidate = ((this.capWord & 0xff) << 8) | ((this.capWord >> 8) & 0xff);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
PacketHeader.prototype.setOrigAddress = function(address) {
|
||||||
|
this.origNode = address.node;
|
||||||
|
|
||||||
|
// See FSC-48
|
||||||
|
if(address.point) {
|
||||||
|
this.origNet = -1;
|
||||||
|
this.auxNet = address.net;
|
||||||
|
} else {
|
||||||
|
this.origNet = address.net;
|
||||||
|
this.auxNet = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.origZone = address.zone;
|
||||||
|
this.origZone2 = address.zone;
|
||||||
|
this.origPoint = address.point || 0;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
PacketHeader.prototype.setDestAddress = function(address) {
|
||||||
|
this.destNode = address.node;
|
||||||
|
this.destNet = address.net;
|
||||||
|
this.destZone = address.zone;
|
||||||
|
this.destZone2 = address.zone;
|
||||||
|
this.destPoint = address.point || 0;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
PacketHeader.prototype.setCreated = function(created) {
|
||||||
|
if(!moment.isMoment(created)) {
|
||||||
|
created = moment(created);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.year = created.year();
|
||||||
|
this.month = created.month();
|
||||||
|
this.day = created.day();
|
||||||
|
this.hour = created.hour();
|
||||||
|
this.minute = created.minute();
|
||||||
|
this.second = created.second();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
PacketHeader.prototype.setPassword = function(password) {
|
||||||
|
this.password = password.substr(0, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Read/Write FTN packets with support for the following formats:
|
// Read/Write FTN packets with support for the following formats:
|
||||||
//
|
//
|
||||||
|
@ -47,7 +134,7 @@ const FTN_MESSAGE_KLUDGE_PREFIX = '\x01';
|
||||||
// * Writeup on differences between type 2, 2.2, and 2+:
|
// * Writeup on differences between type 2, 2.2, and 2+:
|
||||||
// http://walon.org/pub/fidonet/FTSC-nodelists-etc./pkt-types.txt
|
// http://walon.org/pub/fidonet/FTSC-nodelists-etc./pkt-types.txt
|
||||||
//
|
//
|
||||||
function FTNPacket() {
|
function Packet() {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
@ -96,7 +183,8 @@ function FTNPacket() {
|
||||||
.word32lu('prodData')
|
.word32lu('prodData')
|
||||||
.tap(packetHeader => {
|
.tap(packetHeader => {
|
||||||
// Convert password from NULL padded array to string
|
// Convert password from NULL padded array to string
|
||||||
packetHeader.password = ftn.stringFromFTN(packetHeader.password);
|
//packetHeader.password = ftn.stringFromFTN(packetHeader.password);
|
||||||
|
packetHeader.password = strUtil.stringFromNullTermBuffer(packetHeader.password, 'CP437');
|
||||||
|
|
||||||
if(FTN_PACKET_HEADER_TYPE !== packetHeader.packetType) {
|
if(FTN_PACKET_HEADER_TYPE !== packetHeader.packetType) {
|
||||||
cb(new Error('Unsupported header type: ' + packetHeader.packetType));
|
cb(new Error('Unsupported header type: ' + packetHeader.packetType));
|
||||||
|
@ -106,7 +194,7 @@ function FTNPacket() {
|
||||||
//
|
//
|
||||||
// What kind of packet do we really have here?
|
// What kind of packet do we really have here?
|
||||||
//
|
//
|
||||||
// :TODO: adjust values based on version discoverd
|
// :TODO: adjust values based on version discovered
|
||||||
if(FTN_PACKET_BAUD_TYPE_2_2 === packetHeader.baud) {
|
if(FTN_PACKET_BAUD_TYPE_2_2 === packetHeader.baud) {
|
||||||
packetHeader.packetVersion = '2.2';
|
packetHeader.packetVersion = '2.2';
|
||||||
|
|
||||||
|
@ -147,15 +235,16 @@ function FTNPacket() {
|
||||||
//
|
//
|
||||||
packetHeader.created = moment(packetHeader);
|
packetHeader.created = moment(packetHeader);
|
||||||
|
|
||||||
cb(null, packetHeader);
|
let ph = new PacketHeader();
|
||||||
|
_.assign(ph, packetHeader);
|
||||||
|
|
||||||
|
cb(null, ph);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.writePacketHeader = function(packetHeader, ws) {
|
this.writePacketHeader = function(packetHeader, ws) {
|
||||||
let buffer = new Buffer(FTN_PACKET_HEADER_SIZE);
|
let buffer = new Buffer(FTN_PACKET_HEADER_SIZE);
|
||||||
|
|
||||||
// :TODO: write 2, 2.2, or 2+ packet based on packetHeader.packetVersion (def=2+)
|
|
||||||
|
|
||||||
buffer.writeUInt16LE(packetHeader.origNode, 0);
|
buffer.writeUInt16LE(packetHeader.origNode, 0);
|
||||||
buffer.writeUInt16LE(packetHeader.destNode, 2);
|
buffer.writeUInt16LE(packetHeader.destNode, 2);
|
||||||
buffer.writeUInt16LE(packetHeader.created.year(), 4);
|
buffer.writeUInt16LE(packetHeader.created.year(), 4);
|
||||||
|
@ -177,7 +266,8 @@ function FTNPacket() {
|
||||||
buffer.writeUInt16LE(packetHeader.origZone, 34);
|
buffer.writeUInt16LE(packetHeader.origZone, 34);
|
||||||
buffer.writeUInt16LE(packetHeader.destZone, 36);
|
buffer.writeUInt16LE(packetHeader.destZone, 36);
|
||||||
|
|
||||||
switch(packetHeader.packetType) {
|
// :TODO: update header information appropriately for 2 and 2.2
|
||||||
|
switch(packetHeader.packetVersion) {
|
||||||
case '2' :
|
case '2' :
|
||||||
// filler...
|
// filler...
|
||||||
packetHeader.auxNet = 0;
|
packetHeader.auxNet = 0;
|
||||||
|
@ -196,9 +286,20 @@ function FTNPacket() {
|
||||||
packetHeader.hour = 0;
|
packetHeader.hour = 0;
|
||||||
packetHeader.minute = 0;
|
packetHeader.minute = 0;
|
||||||
packetHeader.second = 0;
|
packetHeader.second = 0;
|
||||||
|
|
||||||
|
// :TODO: copy over fields from 2+ -> overriden fields here!
|
||||||
|
|
||||||
|
packetHeader.baud = FTN_PACKET_BAUD_TYPE_2_2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '2+' :
|
case '2+' :
|
||||||
|
const capWordValidateSwapped =
|
||||||
|
((packetHeader.capWordValidate & 0xff) << 8) |
|
||||||
|
((packetHeader.capWordValidate >> 8) & 0xff);
|
||||||
|
|
||||||
|
packetHeader.capWordValidate = capWordValidateSwapped;
|
||||||
|
|
||||||
|
// :TODO: set header appropriate if point
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -355,8 +456,9 @@ function FTNPacket() {
|
||||||
.word16lu('ftn_dest_node')
|
.word16lu('ftn_dest_node')
|
||||||
.word16lu('ftn_orig_network')
|
.word16lu('ftn_orig_network')
|
||||||
.word16lu('ftn_dest_network')
|
.word16lu('ftn_dest_network')
|
||||||
.word8('ftn_attr_flags1')
|
.word16lu('ftn_attr_flags')
|
||||||
.word8('ftn_attr_flags2')
|
//.word8('ftn_attr_flags1')
|
||||||
|
//.word8('ftn_attr_flags2')
|
||||||
.word16lu('ftn_cost')
|
.word16lu('ftn_cost')
|
||||||
.scan('modDateTime', NULL_TERM_BUFFER) // :TODO: 20 bytes max
|
.scan('modDateTime', NULL_TERM_BUFFER) // :TODO: 20 bytes max
|
||||||
.scan('toUserName', NULL_TERM_BUFFER) // :TODO: 36 bytes max
|
.scan('toUserName', NULL_TERM_BUFFER) // :TODO: 36 bytes max
|
||||||
|
@ -404,8 +506,9 @@ function FTNPacket() {
|
||||||
msg.meta.FtnProperty.ftn_dest_node = msgData.ftn_dest_node;
|
msg.meta.FtnProperty.ftn_dest_node = msgData.ftn_dest_node;
|
||||||
msg.meta.FtnProperty.ftn_orig_network = msgData.ftn_orig_network;
|
msg.meta.FtnProperty.ftn_orig_network = msgData.ftn_orig_network;
|
||||||
msg.meta.FtnProperty.ftn_dest_network = msgData.ftn_dest_network;
|
msg.meta.FtnProperty.ftn_dest_network = msgData.ftn_dest_network;
|
||||||
msg.meta.FtnProperty.ftn_attr_flags1 = msgData.ftn_attr_flags1;
|
msg.meta.FtnProperty.ftn_attr_flags = msgData.ftn_attr_flags;
|
||||||
msg.meta.FtnProperty.ftn_attr_flags2 = msgData.ftn_attr_flags2;
|
//msg.meta.FtnProperty.ftn_attr_flags1 = msgData.ftn_attr_flags1;
|
||||||
|
//msg.meta.FtnProperty.ftn_attr_flags2 = msgData.ftn_attr_flags2;
|
||||||
msg.meta.FtnProperty.ftn_cost = msgData.ftn_cost;
|
msg.meta.FtnProperty.ftn_cost = msgData.ftn_cost;
|
||||||
|
|
||||||
self.processMessageBody(msgData.message, function processed(messageBodyData) {
|
self.processMessageBody(msgData.message, function processed(messageBodyData) {
|
||||||
|
@ -457,8 +560,9 @@ function FTNPacket() {
|
||||||
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_dest_node, 4);
|
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_dest_node, 4);
|
||||||
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_orig_network, 6);
|
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_orig_network, 6);
|
||||||
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_dest_network, 8);
|
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_dest_network, 8);
|
||||||
basicHeader.writeUInt8(message.meta.FtnProperty.ftn_attr_flags1, 10);
|
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_attr_flags, 10);
|
||||||
basicHeader.writeUInt8(message.meta.FtnProperty.ftn_attr_flags2, 11);
|
//basicHeader.writeUInt8(message.meta.FtnProperty.ftn_attr_flags1, 10);
|
||||||
|
//basicHeader.writeUInt8(message.meta.FtnProperty.ftn_attr_flags2, 11);
|
||||||
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_cost, 12);
|
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_cost, 12);
|
||||||
|
|
||||||
const dateTimeBuffer = new Buffer(ftn.getDateTimeString(message.modTimestamp) + '\0');
|
const dateTimeBuffer = new Buffer(ftn.getDateTimeString(message.modTimestamp) + '\0');
|
||||||
|
@ -522,20 +626,25 @@ function FTNPacket() {
|
||||||
|
|
||||||
//
|
//
|
||||||
// FTN-0004.001 @ http://ftsc.org/docs/fts-0004.001
|
// FTN-0004.001 @ http://ftsc.org/docs/fts-0004.001
|
||||||
// Origin line should be near the bottom of a message
|
|
||||||
//
|
|
||||||
appendMeta('', message.meta.FtnProperty.ftn_tear_line);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Tear line should be near the bottom of a message
|
// Tear line should be near the bottom of a message
|
||||||
//
|
//
|
||||||
appendMeta('', message.meta.FtnProperty.ftn_origin);
|
if(message.meta.FtnProperty.ftn_tear_line) {
|
||||||
|
msgBody += `${message.meta.FtnProperty.ftn_tear_line}\r`;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Origin line should be near the bottom of a message
|
||||||
|
//
|
||||||
|
if(message.meta.FtnProperty.ftn_origin) {
|
||||||
|
msgBody += `${message.meta.FtnProperty.ftn_origin}\r`;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// FTN-0004.001 @ http://ftsc.org/docs/fts-0004.001
|
// FTN-0004.001 @ http://ftsc.org/docs/fts-0004.001
|
||||||
// SEEN-BY and PATH should be the last lines of a message
|
// SEEN-BY and PATH should be the last lines of a message
|
||||||
//
|
//
|
||||||
appendMeta('SEEN-BY', message.meta.FtnProperty.ftn_seen_by); // note: no ^A (0x01)
|
appendMeta('SEEN-BY', message.meta.FtnProperty.ftn_seen_by); // note: no ^A (0x01)
|
||||||
|
|
||||||
appendMeta('\x01PATH', message.meta.FtnKludge['PATH']);
|
appendMeta('\x01PATH', message.meta.FtnKludge['PATH']);
|
||||||
|
|
||||||
ws.write(iconv.encode(msgBody + '\0', 'CP437'));
|
ws.write(iconv.encode(msgBody + '\0', 'CP437'));
|
||||||
|
@ -564,7 +673,31 @@ function FTNPacket() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
FTNPacket.prototype.read = function(pathOrBuffer, iterator, cb) {
|
//
|
||||||
|
// Message attributes defined in FTS-0001.016
|
||||||
|
// http://ftsc.org/docs/fts-0001.016
|
||||||
|
//
|
||||||
|
Packet.Attribute = {
|
||||||
|
Private : 0x0001,
|
||||||
|
Crash : 0x0002,
|
||||||
|
Received : 0x0004,
|
||||||
|
Sent : 0x0008,
|
||||||
|
FileAttached : 0x0010,
|
||||||
|
InTransit : 0x0020,
|
||||||
|
Orphan : 0x0040,
|
||||||
|
KillSent : 0x0080,
|
||||||
|
Local : 0x0100,
|
||||||
|
Hold : 0x0200,
|
||||||
|
Reserved0 : 0x0400,
|
||||||
|
FileRequest : 0x0800,
|
||||||
|
ReturnReceiptRequest : 0x1000,
|
||||||
|
ReturnReceipt : 0x2000,
|
||||||
|
AuditRequest : 0x4000,
|
||||||
|
FileUpdateRequest : 0x8000,
|
||||||
|
};
|
||||||
|
Object.freeze(Packet.Attribute);
|
||||||
|
|
||||||
|
Packet.prototype.read = function(pathOrBuffer, iterator, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
async.series(
|
async.series(
|
||||||
|
@ -591,32 +724,67 @@ FTNPacket.prototype.read = function(pathOrBuffer, iterator, cb) {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
FTNPacket.prototype.write = function(path, packetHeader, messages, cb) {
|
Packet.prototype.writeStream = function(ws, messages, options) {
|
||||||
packetHeader.packetType = packetHeader.packetType || '2+';
|
if(!_.isBoolean(options.terminatePacket)) {
|
||||||
packetHeader.created = packetHeader.created || moment();
|
options.terminatePacket = true;
|
||||||
packetHeader.baud = packetHeader.baud || 0;
|
}
|
||||||
// :TODO: Other defaults?
|
|
||||||
|
if(_.isObject(options.packetHeader)) {
|
||||||
if(!_.isArray(messages)) {
|
/*
|
||||||
messages = [ messages ] ;
|
let packetHeader = options.packetHeader;
|
||||||
|
|
||||||
|
// default header
|
||||||
|
packetHeader.packetVersion = packetHeader.packetVersion || '2+';
|
||||||
|
packetHeader.created = packetHeader.created || moment();
|
||||||
|
packetHeader.baud = packetHeader.baud || 0;
|
||||||
|
*/
|
||||||
|
this.writePacketHeader(options.packetHeader, ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ws = fs.createWriteStream(path);
|
|
||||||
this.writePacketHeader(packetHeader, ws);
|
|
||||||
|
|
||||||
messages.forEach(msg => {
|
messages.forEach(msg => {
|
||||||
this.writeMessage(msg, ws);
|
this.writeMessage(msg, ws);
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.write(new Buffer( [ 0 ] )); // final extra null term
|
if(true === options.terminatePacket) {
|
||||||
|
ws.write(new Buffer( [ 0 ] )); // final extra null term
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet.prototype.write = function(path, packetHeader, messages) {
|
||||||
|
if(!_.isArray(messages)) {
|
||||||
|
messages = [ messages ];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writeStream(
|
||||||
|
fs.createWriteStream(path), // :TODO: specify mode/etc.
|
||||||
|
messages,
|
||||||
|
{ packetHeader : packetHeader, terminatePacket : true }
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
var ftnPacket = new FTNPacket();
|
const LOCAL_ADDRESS = {
|
||||||
|
zone : 46,
|
||||||
|
net : 1,
|
||||||
|
node : 232,
|
||||||
|
domain : 'l33t.codes',
|
||||||
|
};
|
||||||
|
|
||||||
|
const REMOTE_ADDRESS = {
|
||||||
|
zone : 1,
|
||||||
|
net : 2,
|
||||||
|
node : 218,
|
||||||
|
};
|
||||||
|
|
||||||
|
var packetHeader1 = new PacketHeader();
|
||||||
|
packetHeader1.init(LOCAL_ADDRESS, REMOTE_ADDRESS);
|
||||||
|
console.log(packetHeader1);
|
||||||
|
|
||||||
|
var packet = new Packet();
|
||||||
var theHeader;
|
var theHeader;
|
||||||
var written = false;
|
var written = false;
|
||||||
let messagesToWrite = [];
|
let messagesToWrite = [];
|
||||||
ftnPacket.read(
|
packet.read(
|
||||||
process.argv[2],
|
process.argv[2],
|
||||||
function iterator(dataType, data) {
|
function iterator(dataType, data) {
|
||||||
if('header' === dataType) {
|
if('header' === dataType) {
|
||||||
|
@ -633,7 +801,7 @@ ftnPacket.read(
|
||||||
written = true;
|
written = true;
|
||||||
|
|
||||||
let messages = [ msg ];
|
let messages = [ msg ];
|
||||||
ftnPacket.write('/home/nuskooler/Downloads/ftnout/test1.pkt', theHeader, messages, err => {
|
Packet.write('/home/nuskooler/Downloads/ftnout/test1.pkt', theHeader, messages, err => {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -650,8 +818,13 @@ ftnPacket.read(
|
||||||
console.log(ftn.getMessageIdentifier(msg, address));
|
console.log(ftn.getMessageIdentifier(msg, address));
|
||||||
console.log(ftn.getProductIdentifier())
|
console.log(ftn.getProductIdentifier())
|
||||||
//console.log(ftn.getOrigin(address))
|
//console.log(ftn.getOrigin(address))
|
||||||
console.log(ftn.parseAddress('46:1/232.4@l33t.codes'))
|
//console.log(ftn.parseAddress('46:1/232.4@l33t.codes'))
|
||||||
|
console.log(Address.fromString('46:1/232.4@l33t.codes'));
|
||||||
console.log(ftn.getUTCTimeZoneOffset())
|
console.log(ftn.getUTCTimeZoneOffset())
|
||||||
|
console.log(ftn.getUpdatedSeenByEntries(
|
||||||
|
msg.meta.FtnProperty.ftn_seen_by, '1/107 4/22 4/25 4/10'));
|
||||||
|
console.log(ftn.getUpdatedPathEntries(
|
||||||
|
msg.meta.FtnKludge['PATH'], '1:365/50'))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function completion(err) {
|
function completion(err) {
|
||||||
|
@ -660,7 +833,7 @@ ftnPacket.read(
|
||||||
|
|
||||||
|
|
||||||
console.log(messagesToWrite.length)
|
console.log(messagesToWrite.length)
|
||||||
ftnPacket.write('/home/nuskooler/Downloads/ftnout/test1.pkt', theHeader, messagesToWrite, err => {
|
packet.write('/home/nuskooler/Downloads/ftnout/test1.pkt', theHeader, messagesToWrite, err => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
203
core/ftn_util.js
203
core/ftn_util.js
|
@ -2,7 +2,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var Config = require('./config.js').config;
|
var Config = require('./config.js').config;
|
||||||
|
var Address = require('./ftn_address.js');
|
||||||
|
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
|
@ -18,20 +18,22 @@ var os = require('os');
|
||||||
var packageJson = require('../package.json');
|
var packageJson = require('../package.json');
|
||||||
|
|
||||||
// :TODO: Remove "Ftn" from most of these -- it's implied in the module
|
// :TODO: Remove "Ftn" from most of these -- it's implied in the module
|
||||||
exports.stringFromFTN = stringFromFTN;
|
|
||||||
exports.stringToNullPaddedBuffer = stringToNullPaddedBuffer;
|
exports.stringToNullPaddedBuffer = stringToNullPaddedBuffer;
|
||||||
exports.createMessageUuid = createMessageUuid;
|
exports.createMessageUuid = createMessageUuid;
|
||||||
exports.parseAddress = parseAddress;
|
exports.getDateFromFtnDateTime = getDateFromFtnDateTime;
|
||||||
exports.formatAddress = formatAddress;
|
exports.getDateTimeString = getDateTimeString;
|
||||||
exports.getDateFromFtnDateTime = getDateFromFtnDateTime;
|
|
||||||
exports.getDateTimeString = getDateTimeString;
|
|
||||||
|
|
||||||
exports.getMessageIdentifier = getMessageIdentifier;
|
exports.getMessageIdentifier = getMessageIdentifier;
|
||||||
exports.getProductIdentifier = getProductIdentifier;
|
exports.getProductIdentifier = getProductIdentifier;
|
||||||
exports.getUTCTimeZoneOffset = getUTCTimeZoneOffset;
|
exports.getUTCTimeZoneOffset = getUTCTimeZoneOffset;
|
||||||
exports.getOrigin = getOrigin;
|
exports.getOrigin = getOrigin;
|
||||||
|
exports.getTearLine = getTearLine;
|
||||||
|
exports.getAbbreviatedNetNodeList = getAbbreviatedNetNodeList;
|
||||||
|
exports.parseAbbreviatedNetNodeList = parseAbbreviatedNetNodeList;
|
||||||
|
exports.getUpdatedSeenByEntries = getUpdatedSeenByEntries;
|
||||||
|
exports.getUpdatedPathEntries = getUpdatedPathEntries;
|
||||||
|
|
||||||
exports.getQuotePrefix = getQuotePrefix;
|
exports.getQuotePrefix = getQuotePrefix;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Namespace for RFC-4122 name based UUIDs generated from
|
// Namespace for RFC-4122 name based UUIDs generated from
|
||||||
|
@ -40,23 +42,10 @@ exports.getQuotePrefix = getQuotePrefix;
|
||||||
const ENIGMA_FTN_MSGID_NAMESPACE = uuid.parse('a5c7ae11-420c-4469-a116-0e9a6d8d2654');
|
const ENIGMA_FTN_MSGID_NAMESPACE = uuid.parse('a5c7ae11-420c-4469-a116-0e9a6d8d2654');
|
||||||
|
|
||||||
// Up to 5D FTN address RegExp
|
// Up to 5D FTN address RegExp
|
||||||
const ENIGMA_FTN_ADDRESS_REGEXP = /^([0-9]+):([0-9]+)(\/[0-9]+)?(\.[0-9]+)?(@[a-z0-9\-\.]+)?$/i;
|
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
|
// See list here: https://github.com/Mithgol/node-fidonet-jam
|
||||||
|
|
||||||
// :TODO: proably move this elsewhere as a general method
|
|
||||||
function stringFromFTN(buf, encoding) {
|
|
||||||
var nullPos = buf.length;
|
|
||||||
for(var i = 0; i < buf.length; ++i) {
|
|
||||||
if(0x00 === buf[i]) {
|
|
||||||
nullPos = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return iconv.decode(buf.slice(0, nullPos), encoding || 'utf-8');
|
|
||||||
}
|
|
||||||
|
|
||||||
function stringToNullPaddedBuffer(s, bufLen) {
|
function stringToNullPaddedBuffer(s, bufLen) {
|
||||||
let buffer = new Buffer(bufLen).fill(0x00);
|
let buffer = new Buffer(bufLen).fill(0x00);
|
||||||
let enc = iconv.encode(s, 'CP437').slice(0, bufLen);
|
let enc = iconv.encode(s, 'CP437').slice(0, bufLen);
|
||||||
|
@ -143,57 +132,6 @@ function createMessageUuid(ftnMsgId, ftnArea) {
|
||||||
return uuid.unparse(u); // to string
|
return uuid.unparse(u); // to string
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseAddress(address) {
|
|
||||||
const m = ENIGMA_FTN_ADDRESS_REGEXP.exec(address);
|
|
||||||
|
|
||||||
if(m) {
|
|
||||||
let addr = {
|
|
||||||
zone : parseInt(m[1]),
|
|
||||||
net : parseInt(m[2]),
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// substr(1) on the following to remove the
|
|
||||||
// captured prefix
|
|
||||||
//
|
|
||||||
if(m[3]) {
|
|
||||||
addr.node = parseInt(m[3].substr(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(m[4]) {
|
|
||||||
addr.point = parseInt(m[4].substr(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(m[5]) {
|
|
||||||
addr.domain = m[5].substr(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatAddress(address, dimensions) {
|
|
||||||
let addr = `${address.zone}:${address.net}`;
|
|
||||||
|
|
||||||
// allow for e.g. '4D' or 5
|
|
||||||
const dim = parseInt(dimensions.toString()[0]);
|
|
||||||
|
|
||||||
if(dim >= 3) {
|
|
||||||
addr += `/${address.node}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// missing & .0 are equiv for point
|
|
||||||
if(dim >= 4 && address.point) {
|
|
||||||
addr += `.${addresss.point}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(5 === dim && address.domain) {
|
|
||||||
addr += `@${address.domain.toLowerCase()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMessageSerialNumber(message) {
|
function getMessageSerialNumber(message) {
|
||||||
return ('00000000' + ((Math.floor((Date.now() - Date.UTC(2016, 1, 1)) / 1000) +
|
return ('00000000' + ((Math.floor((Date.now() - Date.UTC(2016, 1, 1)) / 1000) +
|
||||||
message.messageId)).toString(16)).substr(-8);
|
message.messageId)).toString(16)).substr(-8);
|
||||||
|
@ -235,7 +173,8 @@ function getMessageSerialNumber(message) {
|
||||||
// ENiGMA½: <messageId>.<areaTag>@<5dFtnAddress> <serial>
|
// ENiGMA½: <messageId>.<areaTag>@<5dFtnAddress> <serial>
|
||||||
//
|
//
|
||||||
function getMessageIdentifier(message, address) {
|
function getMessageIdentifier(message, address) {
|
||||||
return `${message.messageId}.${message.areaTag.toLowerCase()}@${formatAddress(address, '5D')} ${getMessageSerialNumber(message)}`;
|
const addrStr = new Address(address).toString('5D');
|
||||||
|
return `${message.messageId}.${message.areaTag.toLowerCase()}@${addrStr} ${getMessageSerialNumber(message)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -288,5 +227,113 @@ function getOrigin(address) {
|
||||||
Config.messageNetworks.originName :
|
Config.messageNetworks.originName :
|
||||||
Config.general.boardName;
|
Config.general.boardName;
|
||||||
|
|
||||||
return ` * Origin: ${origin} (${formatAddress(address, '5D')})`;
|
const addrStr = new Address(address).toString('5D');
|
||||||
|
return ` * Origin: ${origin} (${addrStr})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTearLine() {
|
||||||
|
return `--- ENiGMA 1/2 v{$packageJson.version} (${os.platform()}; ${os.arch()}; ${nodeVer})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAbbreviatedNetNodeList(netNodes) {
|
||||||
|
let abbrList = '';
|
||||||
|
let currNet;
|
||||||
|
netNodes.forEach(netNode => {
|
||||||
|
if(currNet !== netNode.net) {
|
||||||
|
abbrList += `${netNode.net}/`;
|
||||||
|
currNet = netNode.net;
|
||||||
|
}
|
||||||
|
abbrList += `${netNode.node} `;
|
||||||
|
});
|
||||||
|
|
||||||
|
return abbrList.trim(); // remove trailing space
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseAbbreviatedNetNodeList(netNodes) {
|
||||||
|
//
|
||||||
|
// Make sure we have an array of objects.
|
||||||
|
// Allow for a single object or string(s)
|
||||||
|
//
|
||||||
|
if(!_.isArray(netNodes)) {
|
||||||
|
if(_.isString(netNodes)) {
|
||||||
|
netNodes = netNodes.split(' ');
|
||||||
|
} else {
|
||||||
|
netNodes = [ netNodes ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Convert any strings to parsed address objects
|
||||||
|
//
|
||||||
|
return netNodes.map(a => {
|
||||||
|
if(_.isObject(a)) {
|
||||||
|
return a;
|
||||||
|
} else {
|
||||||
|
return Address.fromString(a);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return a FTS-0004.001 SEEN-BY entry(s) that include
|
||||||
|
// all pre-existing SEEN-BY entries with the addition
|
||||||
|
// of |additions|.
|
||||||
|
//
|
||||||
|
// See http://ftsc.org/docs/fts-0004.001
|
||||||
|
// and notes at http://ftsc.org/docs/fsc-0043.002.
|
||||||
|
//
|
||||||
|
// For a great write up, see http://www.skepticfiles.org/aj/basics03.htm
|
||||||
|
//
|
||||||
|
// This method returns an sorted array of values, but
|
||||||
|
// not the "SEEN-BY" prefix itself
|
||||||
|
//
|
||||||
|
function getUpdatedSeenByEntries(existingEntries, additions) {
|
||||||
|
/*
|
||||||
|
From FTS-0004:
|
||||||
|
|
||||||
|
"There can be many seen-by lines at the end of Conference
|
||||||
|
Mail messages, and they are the real "meat" of the control
|
||||||
|
information. They are used to determine the systems to
|
||||||
|
receive the exported messages. The format of the line is:
|
||||||
|
|
||||||
|
SEEN-BY: 132/101 113 136/601 1014/1
|
||||||
|
|
||||||
|
The net/node numbers correspond to the net/node numbers of
|
||||||
|
the systems having already received the message. In this way
|
||||||
|
a message is never sent to a system twice. In a conference
|
||||||
|
with many participants the number of seen-by lines can be
|
||||||
|
very large. This line is added if it is not already a part
|
||||||
|
of the message, or added to if it already exists, each time
|
||||||
|
a message is exported to other systems. This is a REQUIRED
|
||||||
|
field, and Conference Mail will not function correctly if
|
||||||
|
this field is not put in place by other Echomail compatible
|
||||||
|
programs."
|
||||||
|
*/
|
||||||
|
existingEntries = existingEntries || [];
|
||||||
|
if(!_.isArray(existingEntries)) {
|
||||||
|
existingEntries = [ existingEntries ];
|
||||||
|
}
|
||||||
|
|
||||||
|
additions = parseAbbreviatedNetNodeList(additions).sort(Address.getComparator());
|
||||||
|
|
||||||
|
//
|
||||||
|
// For now, we'll just append a new SEEN-BY entry
|
||||||
|
//
|
||||||
|
// :TODO: we should at least try and update what is already there in a smart way
|
||||||
|
existingEntries.push(getAbbreviatedNetNodeList(additions));
|
||||||
|
return existingEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUpdatedPathEntries(existingEntries, localAddress) {
|
||||||
|
// :TODO: append to PATH in a smart way! We shoudl try to fit at least the last existing line
|
||||||
|
|
||||||
|
existingEntries = existingEntries || [];
|
||||||
|
if(!_.isArray(existingEntries)) {
|
||||||
|
existingEntries = [ existingEntries ];
|
||||||
|
}
|
||||||
|
|
||||||
|
existingEntries.push(getAbbreviatedNetNodeList(
|
||||||
|
parseAbbreviatedNetNodeList(localAddress)));
|
||||||
|
|
||||||
|
return existingEntries;
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,8 +109,9 @@ Message.FtnPropertyNames = {
|
||||||
FtnDestNode : 'ftn_dest_node',
|
FtnDestNode : 'ftn_dest_node',
|
||||||
FtnOrigNetwork : 'ftn_orig_network',
|
FtnOrigNetwork : 'ftn_orig_network',
|
||||||
FtnDestNetwork : 'ftn_dest_network',
|
FtnDestNetwork : 'ftn_dest_network',
|
||||||
FtnAttrFlags1 : 'ftn_attr_flags1',
|
FtnAttrFlags : 'ftn_attr_flags',
|
||||||
FtnAttrFlags2 : 'ftn_attr_flags2',
|
//FtnAttrFlags1 : 'ftn_attr_flags1',
|
||||||
|
//FtnAttrFlags2 : 'ftn_attr_flags2',
|
||||||
FtnCost : 'ftn_cost',
|
FtnCost : 'ftn_cost',
|
||||||
FtnOrigZone : 'ftn_orig_zone',
|
FtnOrigZone : 'ftn_orig_zone',
|
||||||
FtnDestZone : 'ftn_dest_zone',
|
FtnDestZone : 'ftn_dest_zone',
|
||||||
|
|
|
@ -2,8 +2,12 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// ENiGMA½
|
// ENiGMA½
|
||||||
var MessageScanTossModule = require('../scan_toss_module.js').MessageScanTossModule;
|
let MessageScanTossModule = require('../scan_toss_module.js').MessageScanTossModule;
|
||||||
var Config = require('../config.js').config;
|
let Config = require('../config.js').config;
|
||||||
|
let ftnMailpacket = require('../ftn_mail_packet.js');
|
||||||
|
let ftnUtil = require('../ftn_util.js');
|
||||||
|
|
||||||
|
let moment = require('moment');
|
||||||
|
|
||||||
exports.moduleInfo = {
|
exports.moduleInfo = {
|
||||||
name : 'FTN',
|
name : 'FTN',
|
||||||
|
@ -18,7 +22,60 @@ function FTNMessageScanTossModule() {
|
||||||
|
|
||||||
this.config = Config.scannerTossers.ftn_bso;
|
this.config = Config.scannerTossers.ftn_bso;
|
||||||
|
|
||||||
|
this.createMessagePacket = function(message, config) {
|
||||||
|
this.prepareMessage(message);
|
||||||
|
|
||||||
|
let packet = new ftnMailPacket.Packet();
|
||||||
|
|
||||||
|
let packetHeader = new ftnMailpacket.PacketHeader();
|
||||||
|
packetHeader.init(
|
||||||
|
config.network.localAddress,
|
||||||
|
config.remoteAddress);
|
||||||
|
|
||||||
|
packetHeader.setPassword(config.remoteNode.packetPassword || '');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.prepareMessage = function(message, config) {
|
||||||
|
//
|
||||||
|
// Set various FTN kludges/etc.
|
||||||
|
//
|
||||||
|
message.meta.FtnProperty = message.meta.FtnProperty || {};
|
||||||
|
message.meta.FtnProperty.ftn_orig_node = config.network.localAddress.node;
|
||||||
|
message.meta.FtnProperty.ftn_dest_node = config.remoteAddress.node;
|
||||||
|
message.meta.FtnProperty.ftn_orig_network = config.network.localAddress.net;
|
||||||
|
message.meta.FtnProperty.ftn_dest_network = config.remoteAddress.net;
|
||||||
|
// :TODO: attr1 & 2
|
||||||
|
message.meta.FtnProperty.ftn_cost = 0;
|
||||||
|
|
||||||
|
message.meta.FtnProperty.ftn_tear_line = ftnUtil.getTearLine();
|
||||||
|
message.meta.FtnProperty.ftn_origin = ftnUtil.getOrigin(config.network.localAddress);
|
||||||
|
|
||||||
|
if(message.areaTag) {
|
||||||
|
message.meta.FtnProperty.ftn_area = message.areaTag;
|
||||||
|
} else {
|
||||||
|
// :TODO: add "Via" line -- FSP-1010
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// When exporting messages, we should create/update SEEN-BY
|
||||||
|
// with remote address(s) we are exporting to.
|
||||||
|
//
|
||||||
|
message.meta.FtnProperty.ftn_seen_by =
|
||||||
|
ftnUtil.getUpdatedSeenByEntries(
|
||||||
|
message.meta.FtnProperty.ftn_seen_by,
|
||||||
|
Config.messageNetworks.ftn.areas[message.areaTag].uplinks
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// And create/update PATH for ourself
|
||||||
|
//
|
||||||
|
message.meta.FtnKludge['PATH'] =
|
||||||
|
ftnUtil.getUpdatedPathEntries(
|
||||||
|
message.meta.FtnKludge['PATH'],
|
||||||
|
config.network.localAddress.node
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
require('util').inherits(FTNMessageScanTossModule, MessageScanTossModule);
|
require('util').inherits(FTNMessageScanTossModule, MessageScanTossModule);
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
/* jslint node: true */
|
/* jslint node: true */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var miscUtil = require('./misc_util.js');
|
let miscUtil = require('./misc_util.js');
|
||||||
|
|
||||||
|
let iconv = require('iconv-lite');
|
||||||
|
|
||||||
exports.stylizeString = stylizeString;
|
exports.stylizeString = stylizeString;
|
||||||
exports.pad = pad;
|
exports.pad = pad;
|
||||||
exports.replaceAt = replaceAt;
|
exports.replaceAt = replaceAt;
|
||||||
exports.isPrintable = isPrintable;
|
exports.isPrintable = isPrintable;
|
||||||
exports.debugEscapedString = debugEscapedString;
|
exports.debugEscapedString = debugEscapedString;
|
||||||
|
exports.stringFromNullTermBuffer = stringFromNullTermBuffer;
|
||||||
|
|
||||||
// :TODO: create Unicode verison of this
|
// :TODO: create Unicode verison of this
|
||||||
var VOWELS = [ 'a', 'e', 'i', 'o', 'u' ];
|
var VOWELS = [ 'a', 'e', 'i', 'o', 'u' ];
|
||||||
|
@ -176,6 +178,23 @@ function debugEscapedString(s) {
|
||||||
return JSON.stringify(s).slice(1, -1);
|
return JSON.stringify(s).slice(1, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stringFromNullTermBuffer(buf, encoding) {
|
||||||
|
/*var nullPos = buf.length;
|
||||||
|
for(var i = 0; i < buf.length; ++i) {
|
||||||
|
if(0x00 === buf[i]) {
|
||||||
|
nullPos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
let nullPos = buf.indexOf(new Buffer( [ 0x00 ] ));
|
||||||
|
if(-1 === nullPos) {
|
||||||
|
nullPos = buf.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return iconv.decode(buf.slice(0, nullPos), encoding || 'utf-8');
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Extend String.format's object syntax with some modifiers
|
// Extend String.format's object syntax with some modifiers
|
||||||
// e.g.: '{username!styleL33t}'.format( { username : 'Leet User' } ) -> "L33t U53r"
|
// e.g.: '{username!styleL33t}'.format( { username : 'Leet User' } ) -> "L33t U53r"
|
||||||
|
|
Loading…
Reference in New Issue