* Handle import of NetMail messages

* Add NetMail aliases support (name -> localname lookup, e.g. "root" -> "NuSkooler"
* Minor code changes / cleanup
This commit is contained in:
Bryan Ashby 2018-01-01 13:32:55 -07:00
parent 11a19d899e
commit 6d929237d2
3 changed files with 102 additions and 63 deletions

View File

@ -264,12 +264,12 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
isEditMode() {
return 'edit' === this.editorMode;
}
isViewMode() {
return 'view' === this.editorMode;
}
isLocalEmail() {
isPrivateMail() {
return Message.WellKnownAreaTags.Private === this.messageAreaTag;
}
@ -411,7 +411,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
return callback(null);
},
function populateLocalUserInfo(callback) {
if(self.isLocalEmail()) {
if(self.isPrivateMail()) {
self.message.setLocalFromUserId(self.client.user.userId);
if(self.toUserId > 0) {

View File

@ -347,13 +347,13 @@ function getNewMessageDataInAreaForUserSql(userId, areaTag, lastMessageId, what)
'COUNT() AS count' :
'message_id, message_uuid, reply_to_message_id, to_user_name, from_user_name, subject, modified_timestamp, view_count';
let sql =
let sql =
`SELECT ${selectWhat}
FROM message
WHERE area_tag = "${areaTag}" AND message_id > ${lastMessageId}`;
if(Message.isPrivateAreaTag(areaTag)) {
sql +=
sql +=
` AND message_id in (
SELECT message_id
FROM message_meta

View File

@ -20,6 +20,7 @@ const getDescFromFileName = require('../file_base_area.js').getDescFromFileNa
const copyFileWithCollisionHandling = require('../file_util.js').copyFileWithCollisionHandling;
const getAreaStorageDirectoryByTag = require('../file_base_area.js').getAreaStorageDirectoryByTag;
const isValidStorageTag = require('../file_base_area.js').isValidStorageTag;
const User = require('../user.js');
// deps
const moment = require('moment');
@ -310,22 +311,17 @@ function FTNMessageScanTossModule() {
message.meta.FtnProperty = message.meta.FtnProperty || {};
message.meta.FtnKludge = message.meta.FtnKludge || {};
// :TODO: Only set DEST information for EchoMail - NetMail should already have it in message
message.meta.FtnProperty.ftn_orig_node = options.network.localAddress.node;
//message.meta.FtnProperty.ftn_dest_node = options.destAddress.node;
message.meta.FtnProperty.ftn_orig_network = options.network.localAddress.net;
//message.meta.FtnProperty.ftn_dest_network = options.destAddress.net;
message.meta.FtnProperty.ftn_cost = 0;
// tear line and origin can both go in EchoMail & NetMail
message.meta.FtnProperty.ftn_tear_line = ftnUtil.getTearLine();
message.meta.FtnProperty.ftn_origin = ftnUtil.getOrigin(options.network.localAddress);
// :TODO: Need an explicit isNetMail() check or more generally
let ftnAttribute =
ftnMailPacket.Packet.Attribute.Local; // message from our system
let ftnAttribute = ftnMailPacket.Packet.Attribute.Local; // message from our system
if(message.isPrivate()) {
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)));
@ -438,7 +434,6 @@ function FTNMessageScanTossModule() {
options.encoding = encoding; // save for later
message.meta.FtnKludge.CHRS = ftnUtil.getCharacterSetIdentifierByEncoding(encoding);
// :TODO: FLAGS kludge?
};
this.setReplyKludgeFromReplyToMsgId = function(message, cb) {
@ -565,7 +560,6 @@ function FTNMessageScanTossModule() {
async.series(
[
function generalPrep(callback) {
// :TODO: Double check Via spec -- seems like it may be wrong
self.prepareMessage(message, exportOpts);
return self.setReplyKludgeFromReplyToMsgId(message, callback);
@ -886,8 +880,6 @@ function FTNMessageScanTossModule() {
return callback(err);
}
exportOpts.nodeConfig = config;
exportOpts.destAddress = routeAddress;
exportOpts.fileCase = config.fileCase || 'lower';
@ -904,9 +896,8 @@ function FTNMessageScanTossModule() {
});
},
function createOutgoingDir(callback) {
// ensure outgoing NetMail directory exists
// 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);
@ -915,7 +906,6 @@ function FTNMessageScanTossModule() {
const newExt = exportOpts.fileCase === 'lower' ? '.pkt' : '.PKT';
exportOpts.exportedToPath = paths.join(
exportOpts.outgoingDir,
//Config.scannerTossers.ftn_bso.paths.outboundNetMail,
`${paths.basename(exportOpts.pktFileName, paths.extname(exportOpts.pktFileName))}${newExt}`
);
@ -1107,14 +1097,29 @@ function FTNMessageScanTossModule() {
});
};
this.importEchoMailToArea = function(localAreaTag, header, message, cb) {
this.getLocalUserNameFromAlias = function(lookup) {
lookup = lookup.toLowerCase();
const aliases = _.get(Config, 'messageNetworks.ftn.netMail.aliases');
if(!aliases) {
return lookup; // keep orig
}
const alias = _.find(aliases, (localName, alias) => {
return alias.toLowerCase() === lookup;
});
return alias || lookup;
};
this.importMailToArea = function(config, header, message, cb) {
async.series(
[
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'));
return callback(_.isString(localNetworkName) ? null : new Error('Packet destination is not us'));
},
function checkForDupeMSGID(callback) {
//
@ -1135,23 +1140,49 @@ function FTNMessageScanTossModule() {
});
},
function basicSetup(callback) {
message.areaTag = localAreaTag;
message.areaTag = config.localAreaTag;
//
// If we *allow* dupes (disabled by default), then just generate
// a random UUID. Otherwise, don't assign the UUID just yet. It will be
// generated at persist() time and should be consistent across import/exports
//
if(Config.messageNetworks.ftn.areas[localAreaTag].allowDupes) {
if(true === _.get(Config, [ 'messageNetworks', 'ftn', 'areas', config.localAreaTag, 'allowDupes' ], false)) {
// just generate a UUID & therefor always allow for dupes
message.uuid = uuidV4();
}
callback(null);
return callback(null);
},
function setReplyToMessageId(callback) {
self.setReplyToMsgIdFtnReplyKludge(message, () => {
callback(null);
return callback(null);
});
},
function setupPrivateMessage(callback) {
//
// If this is a private message (e.g. NetMail) we set the local user ID
//
if(Message.WellKnownAreaTags.Private !== config.localAreaTag) {
return callback(null);
}
const lookupName = self.getLocalUserNameFromAlias(message.toUserName);
// :TODO: take into account aliasing, e.g. "root" -> SysOp
User.getUserIdAndName(lookupName, (err, localToUserId, localUserName) => {
if(err) {
return callback(Errors.DoesNotExist(`Could not get local user ID for "${message.toUserName}": ${err.message}`));
}
// we do this after such that error cases can be preseved above
if(lookupName !== message.toUserName) {
message.toUserName = localUserName;
}
// set the meta information - used elsehwere for retrieval
message.meta.System[Message.SystemMetaNames.LocalToUserID] = localToUserId;
return callback(null);
});
},
function persistImport(callback) {
@ -1160,7 +1191,7 @@ function FTNMessageScanTossModule() {
// save to disc
message.persist(err => {
callback(err);
return callback(err);
});
}
],
@ -1214,45 +1245,15 @@ function FTNMessageScanTossModule() {
const message = entryData;
const areaTag = message.meta.FtnProperty.ftn_area;
let localAreaTag;
if(areaTag) {
//
// EchoMail
//
const localAreaTag = self.getLocalAreaTagByFtnAreaTag(areaTag);
if(localAreaTag) {
message.uuid = Message.createMessageUUID(
localAreaTag,
message.modTimestamp,
message.subject,
message.message);
localAreaTag = self.getLocalAreaTagByFtnAreaTag(areaTag);
self.appendTearAndOrigin(message);
self.importEchoMailToArea(localAreaTag, packetHeader, message, err => {
if(err) {
// bump area fail stats
importStats.areaFail[localAreaTag] = (importStats.areaFail[localAreaTag] || 0) + 1;
if('SQLITE_CONSTRAINT' === err.code || 'DUPE_MSGID' === err.code) {
const msgId = _.has(message.meta, 'FtnKludge.MSGID') ? message.meta.FtnKludge.MSGID : 'N/A';
Log.info(
{ area : localAreaTag, subject : message.subject, uuid : message.uuid, MSGID : msgId },
'Not importing non-unique message');
return next(null);
}
} else {
// bump area success
importStats.areaSuccess[localAreaTag] = (importStats.areaSuccess[localAreaTag] || 0) + 1;
}
return next(err);
});
} else {
if(!localAreaTag) {
//
// No local area configured for this import
//
// :TODO: Handle the "catch all" case, if configured
// :TODO: Handle the "catch all" area bucket case if configured
Log.warn( { areaTag : areaTag }, 'No local area configured for this packet file!');
// bump generic failure
@ -1262,11 +1263,49 @@ function FTNMessageScanTossModule() {
}
} else {
//
// NetMail
// No area tag: If marked private in attributes, this is a NetMail
//
Log.warn('NetMail import not yet implemented!');
return next(null);
if(message.meta.FtnProperty.ftn_attr_flags & ftnMailPacket.Packet.Attribute.Private) {
localAreaTag = Message.WellKnownAreaTags.Private;
} else {
Log.warn('Non-private message without area tag');
importStats.otherFail += 1;
return next(null);
}
}
message.uuid = Message.createMessageUUID(
localAreaTag,
message.modTimestamp,
message.subject,
message.message);
self.appendTearAndOrigin(message);
const importConfig = {
localAreaTag : localAreaTag,
};
self.importMailToArea(importConfig, packetHeader, message, err => {
if(err) {
// bump area fail stats
importStats.areaFail[localAreaTag] = (importStats.areaFail[localAreaTag] || 0) + 1;
if('SQLITE_CONSTRAINT' === err.code || 'DUPE_MSGID' === err.code) {
const msgId = _.has(message.meta, 'FtnKludge.MSGID') ? message.meta.FtnKludge.MSGID : 'N/A';
Log.info(
{ area : localAreaTag, subject : message.subject, uuid : message.uuid, MSGID : msgId },
'Not importing non-unique message');
return next(null);
}
} else {
// bump area success
importStats.areaSuccess[localAreaTag] = (importStats.areaSuccess[localAreaTag] || 0) + 1;
}
return next(err);
});
}
}, err => {
//