NetMail non-HUB fixes

* Properly separate FTN *packet* header vs *message* header DST/SRC information
* Change routes{} handling: These are now *require* for out-of-HUB routing such that Enig will know where to send messages
This commit is contained in:
Bryan Ashby 2018-01-20 15:16:35 -07:00
parent b1cea5edd7
commit afe0c88cfc
3 changed files with 113 additions and 93 deletions

View File

@ -524,13 +524,13 @@ function Packet(options) {
);
};
this.parsePacketMessages = function(packetBuffer, iterator, cb) {
this.parsePacketMessages = function(header, packetBuffer, iterator, cb) {
binary.parse(packetBuffer)
.word16lu('messageType')
.word16lu('ftn_orig_node')
.word16lu('ftn_dest_node')
.word16lu('ftn_orig_network')
.word16lu('ftn_dest_network')
.word16lu('ftn_msg_orig_node')
.word16lu('ftn_msg_dest_node')
.word16lu('ftn_msg_orig_net')
.word16lu('ftn_msg_dest_net')
.word16lu('ftn_attr_flags')
.word16lu('ftn_cost')
.scan('modDateTime', NULL_TERM_BUFFER) // :TODO: 20 bytes max
@ -569,20 +569,28 @@ function Packet(options) {
// contain an origin line, kludges, SAUCE in the case
// of ANSI files, etc.
//
let msg = new Message( {
const msg = new Message( {
toUserName : convMsgData.toUserName,
fromUserName : convMsgData.fromUserName,
subject : convMsgData.subject,
modTimestamp : ftn.getDateFromFtnDateTime(convMsgData.modDateTime),
});
msg.meta.FtnProperty = {};
msg.meta.FtnProperty.ftn_orig_node = msgData.ftn_orig_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_dest_network = msgData.ftn_dest_network;
msg.meta.FtnProperty.ftn_attr_flags = msgData.ftn_attr_flags;
msg.meta.FtnProperty.ftn_cost = msgData.ftn_cost;
// :TODO: When non-private (e.g. EchoMail), attempt to extract SRC from MSGID vs headers, when avail (or Orgin line? research further)
msg.meta.FtnProperty = {
ftn_orig_node : header.origNode,
ftn_dest_node : header.destNode,
ftn_orig_network : header.origNet,
ftn_dest_network : header.destNet,
ftn_attr_flags : msgData.ftn_attr_flags,
ftn_cost : msgData.ftn_cost,
ftn_msg_orig_node : msgData.ftn_msg_orig_node,
ftn_msg_dest_node : msgData.ftn_msg_dest_node,
ftn_msg_orig_net : msgData.ftn_msg_orig_net,
ftn_msg_dest_net : msgData.ftn_msg_dest_net,
};
self.processMessageBody(msgData.message, messageBodyData => {
msg.message = messageBodyData.message;
@ -622,11 +630,11 @@ function Packet(options) {
const nextBuf = packetBuffer.slice(read);
if(nextBuf.length > 0) {
let next = function(e) {
const next = function(e) {
if(e) {
cb(e);
} else {
self.parsePacketMessages(nextBuf, iterator, cb);
self.parsePacketMessages(header, nextBuf, iterator, cb);
}
};
@ -651,6 +659,10 @@ function Packet(options) {
Message.FtnPropertyNames.FtnOrigPoint,
Message.FtnPropertyNames.FtnDestPoint,
Message.FtnPropertyNames.FtnAttribute,
Message.FtnPropertyNames.FtnMsgOrigNode,
Message.FtnPropertyNames.FtnMsgDestNode,
Message.FtnPropertyNames.FtnMsgOrigNet,
Message.FtnPropertyNames.FtnMsgDestNet,
].forEach( propName => {
if(message.meta.FtnProperty[propName]) {
message.meta.FtnProperty[propName] = parseInt(message.meta.FtnProperty[propName]) || 0;
@ -658,6 +670,25 @@ function Packet(options) {
});
};
this.writeMessageHeader = function(message, buf) {
// ensure address FtnProperties are numbers
self.sanatizeFtnProperties(message);
const destNode = message.meta.FtnProperty.ftn_msg_dest_node || message.meta.FtnProperty.ftn_dest_node;
const destNet = message.meta.FtnProperty.ftn_msg_dest_net || message.meta.FtnProperty.ftn_dest_network;
buf.writeUInt16LE(FTN_PACKET_MESSAGE_TYPE, 0);
buf.writeUInt16LE(message.meta.FtnProperty.ftn_orig_node, 2);
buf.writeUInt16LE(destNode, 4);
buf.writeUInt16LE(message.meta.FtnProperty.ftn_orig_network, 6);
buf.writeUInt16LE(destNet, 8);
buf.writeUInt16LE(message.meta.FtnProperty.ftn_attr_flags, 10);
buf.writeUInt16LE(message.meta.FtnProperty.ftn_cost, 12);
const dateTimeBuffer = new Buffer(ftn.getDateTimeString(message.modTimestamp) + '\0');
dateTimeBuffer.copy(buf, 14);
};
this.getMessageEntryBuffer = function(message, options, cb) {
function getAppendMeta(k, m, sepChar=':') {
@ -678,20 +709,7 @@ function Packet(options) {
[
function prepareHeaderAndKludges(callback) {
const basicHeader = new Buffer(34);
// ensure address FtnProperties are numbers
self.sanatizeFtnProperties(message);
basicHeader.writeUInt16LE(FTN_PACKET_MESSAGE_TYPE, 0);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_orig_node, 2);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_dest_node, 4);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_orig_network, 6);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_dest_network, 8);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_attr_flags, 10);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_cost, 12);
const dateTimeBuffer = new Buffer(ftn.getDateTimeString(message.modTimestamp) + '\0');
dateTimeBuffer.copy(basicHeader, 14);
self.writeMessageHeader(message, basicHeader);
//
// To, from, and subject must be NULL term'd and have max lengths as per spec.
@ -808,17 +826,7 @@ function Packet(options) {
this.writeMessage = function(message, ws, options) {
let basicHeader = new Buffer(34);
basicHeader.writeUInt16LE(FTN_PACKET_MESSAGE_TYPE, 0);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_orig_node, 2);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_dest_node, 4);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_orig_network, 6);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_dest_network, 8);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_attr_flags, 10);
basicHeader.writeUInt16LE(message.meta.FtnProperty.ftn_cost, 12);
const dateTimeBuffer = new Buffer(ftn.getDateTimeString(message.modTimestamp) + '\0');
dateTimeBuffer.copy(basicHeader, 14);
self.writeMessageHeader(message, basicHeader);
ws.write(basicHeader);
@ -911,7 +919,7 @@ function Packet(options) {
};
this.parsePacketBuffer = function(packetBuffer, iterator, cb) {
async.series(
async.waterfall(
[
function processHeader(callback) {
self.parsePacketHeader(packetBuffer, (err, header) => {
@ -919,15 +927,16 @@ function Packet(options) {
return callback(err);
}
let next = function(e) {
callback(e);
const next = function(e) {
return callback(e, header);
};
iterator('header', header, next);
});
},
function processMessages(callback) {
function processMessages(header, callback) {
self.parsePacketMessages(
header,
packetBuffer.slice(FTN_PACKET_HEADER_SIZE),
iterator,
callback);

View File

@ -116,8 +116,10 @@ Message.StateFlags0 = {
};
Message.FtnPropertyNames = {
// packet header oriented
FtnOrigNode : 'ftn_orig_node',
FtnDestNode : 'ftn_dest_node',
// :TODO: rename these to ftn_*_net vs network - ensure things won't break, may need mapping
FtnOrigNetwork : 'ftn_orig_network',
FtnDestNetwork : 'ftn_dest_network',
FtnAttrFlags : 'ftn_attr_flags',
@ -127,6 +129,12 @@ Message.FtnPropertyNames = {
FtnOrigPoint : 'ftn_orig_point',
FtnDestPoint : 'ftn_dest_point',
// message header oriented
FtnMsgOrigNode : 'ftn_msg_orig_node',
FtnMsgDestNode : 'ftn_msg_dest_node',
FtnMsgOrigNet : 'ftn_msg_orig_net',
FtnMsgDestNet : 'ftn_msg_dest_net',
FtnAttribute : 'ftn_attribute',
FtnTearLine : 'ftn_tear_line', // http://ftsc.org/docs/fts-0004.001

View File

@ -306,12 +306,26 @@ function FTNMessageScanTossModule() {
//
const localAddress = new Address(options.network.localAddress); // ensure we have an Address obj not a string version
// :TODO: create Address.toMeta() / similar
message.meta.FtnProperty = message.meta.FtnProperty || {};
message.meta.FtnKludge = message.meta.FtnKludge || {};
message.meta.FtnProperty.ftn_orig_node = localAddress.node;
message.meta.FtnProperty.ftn_orig_network = localAddress.net;
message.meta.FtnProperty.ftn_cost = 0;
message.meta.FtnProperty.ftn_orig_node = localAddress.node;
message.meta.FtnProperty.ftn_orig_network = localAddress.net;
message.meta.FtnProperty.ftn_cost = 0;
message.meta.FtnProperty.ftn_msg_orig_node = localAddress.node;
message.meta.FtnProperty.ftn_msg_orig_net = localAddress.net;
const destAddress = options.routeAddress || options.destAddress;
message.meta.FtnProperty.ftn_dest_node = destAddress.node;
message.meta.FtnProperty.ftn_dest_network = destAddress.net;
if(destAddress.zone) {
message.meta.FtnProperty.ftn_dest_zone = destAddress.zone;
}
if(destAddress.point) {
message.meta.FtnProperty.ftn_dest_point = destAddress.point;
}
// tear line and origin can both go in EchoMail & NetMail
message.meta.FtnProperty.ftn_tear_line = ftnUtil.getTearLine();
@ -320,9 +334,11 @@ function FTNMessageScanTossModule() {
let ftnAttribute = ftnMailPacket.Packet.Attribute.Local; // message from our system
if(self.isNetMailMessage(message)) {
// These should be set for Private/NetMail already
assert(_.isNumber(parseInt(message.meta.FtnProperty.ftn_dest_node)));
assert(_.isNumber(parseInt(message.meta.FtnProperty.ftn_dest_network)));
//
// Set route and message destination properties -- they may differ
//
message.meta.FtnProperty.ftn_msg_dest_node = options.destAddress.node;
message.meta.FtnProperty.ftn_msg_dest_net = options.destAddress.net;
ftnAttribute |= ftnMailPacket.Packet.Attribute.Private;
@ -353,10 +369,6 @@ function FTNMessageScanTossModule() {
message.meta.FtnKludge.TOPT = options.destAddress.point;
}
} else {
// We need to set some destination info for EchoMail
message.meta.FtnProperty.ftn_dest_node = options.destAddress.node;
message.meta.FtnProperty.ftn_dest_network = options.destAddress.net;
//
// Set appropriate attribute flag for export type
//
@ -573,7 +585,7 @@ function FTNMessageScanTossModule() {
const packetHeader = new ftnMailPacket.PacketHeader(
exportOpts.network.localAddress,
exportOpts.destAddress,
exportOpts.routeAddress,
exportOpts.nodeConfig.packetType
);
@ -801,57 +813,44 @@ function FTNMessageScanTossModule() {
return _.find(routes, (route, addrWildcard) => {
return dstAddr.isPatternMatch(addrWildcard);
});
/*
const route = _.find(routes, (route, addrWildcard) => {
return dstAddr.isPatternMatch(addrWildcard);
});
if(route && route.address) {
return Address.fromString(route.address);
}
*/
};
this.getAcceptableNetMailNetworkInfoFromAddress = function(dstAddr, cb) {
this.getNetMailRouteInfoFromAddress = function(destAddress, cb) {
//
// Attempt to find an acceptable network configuration using the following
// lookup order (most to least explicit config):
// Attempt to find route information for |destAddress|:
//
// 1) Routes: messageNetworks.ftn.netMail.routes{} -> scannerTossers.ftn_bso.nodes{} -> config
// - Where we send may not be where dstAddress is (it's routed!)
// - Where we send may not be where destAddress is (it's routed!)
// 2) Direct to nodes: scannerTossers.ftn_bso.nodes{} -> config
// - Where we send is direct to dstAddr
// - Where we send is direct to destAddress
//
// In both cases, attempt to look up Zone:Net/* to discover local "from" network/address
// falling back to Config.scannerTossers.ftn_bso.defaultNetwork
//
const route = this.getNetMailRoute(dstAddr);
const route = this.getNetMailRoute(destAddress);
let routeAddress;
let networkName;
let isRouted;
if(route) {
routeAddress = Address.fromString(route.address);
networkName = route.network;
isRouted = true;
} else {
routeAddress = dstAddr;
routeAddress = destAddress;
isRouted = false;
}
networkName = networkName ||
this.getNetworkNameByAddressPattern(`${routeAddress.zone}:${routeAddress.net}/*`) ||
Config.scannerTossers.ftn_bso.defaultNetwork
;
networkName = networkName || this.getNetworkNameByAddress(routeAddress);
const config = _.find(this.moduleConfig.nodes, (node, nodeAddrWildcard) => {
return routeAddress.isPatternMatch(nodeAddrWildcard);
}) || {
packetType : '2+',
encoding : Config.scannerTossers.ftn_bso.packetMsgEncoding,
};
}) || { packetType : '2+', encoding : Config.scannerTossers.ftn_bso.packetMsgEncoding };
// we should never be failing here; we may just be using defaults.
return cb(
config ? null : Errors.DoesNotExist(`No configuration found for ${dstAddr.toString()}`),
config, routeAddress, networkName
networkName ? null : Errors.DoesNotExist(`No NetMail route for ${destAddress.toString()}`),
{ destAddress, routeAddress, networkName, config, isRouted }
);
};
@ -876,21 +875,22 @@ function FTNMessageScanTossModule() {
function discoverUplink(callback) {
const dstAddr = new Address(message.meta.System[Message.SystemMetaNames.RemoteToUser]);
return self.getAcceptableNetMailNetworkInfoFromAddress(dstAddr, (err, config, routeAddress, networkName) => {
self.getNetMailRouteInfoFromAddress(dstAddr, (err, routeInfo) => {
if(err) {
return callback(err);
}
exportOpts.nodeConfig = config;
exportOpts.destAddress = routeAddress;
exportOpts.fileCase = config.fileCase || 'lower';
exportOpts.network = Config.messageNetworks.ftn.networks[networkName];
exportOpts.networkName = networkName;
exportOpts.nodeConfig = routeInfo.config;
exportOpts.destAddress = dstAddr;
exportOpts.routeAddress = routeInfo.routeAddress;
exportOpts.fileCase = routeInfo.config.fileCase || 'lower';
exportOpts.network = Config.messageNetworks.ftn.networks[routeInfo.networkName];
exportOpts.networkName = routeInfo.networkName;
exportOpts.outgoingDir = self.getOutgoingEchoMailPacketDir(exportOpts.networkName, exportOpts.destAddress);
exportOpts.exportType = self.getExportType(config);
exportOpts.exportType = self.getExportType(routeInfo.config);
if(!exportOpts.network) {
return callback(Errors.DoesNotExist(`No configuration found for network ${networkName}`));
return callback(Errors.DoesNotExist(`No configuration found for network ${routeInfo.networkName}`));
}
return callback(null);
@ -937,12 +937,15 @@ function FTNMessageScanTossModule() {
],
err => {
if(err) {
Log.warn( { error :err.message }, 'Error exporting message' );
Log.warn( { error : err.message }, 'Error exporting message' );
}
return nextMessageOrUuid(null);
}
);
}, err => {
if(err) {
Log.warn( { error : err.message }, 'Error(s) during NetMail export');
}
return cb(err);
});
};
@ -962,6 +965,7 @@ function FTNMessageScanTossModule() {
fileCase : self.moduleConfig.nodes[nodeConfigKey].fileCase || 'lower',
};
if(_.isString(exportOpts.network.localAddress)) {
exportOpts.network.localAddress = Address.fromString(exportOpts.network.localAddress);
}
@ -2031,8 +2035,7 @@ function FTNMessageScanTossModule() {
this.isNetMailMessage = function(message) {
return message.isPrivate() &&
null === _.get(message, 'meta.System.LocalToUserID', null) &&
Message.AddressFlavor.FTN === _.get(message, 'meta.System.external_flavor', null)
;
Message.AddressFlavor.FTN === _.get(message, 'meta.System.external_flavor', null);
};
}