* Add concept of external flavor to import/exported mails, e.g. 'ftn'
* Add to/from remote user meta for opaqe addrs, e.g. 'ftn' flavor can use FTN-style addresses * Allow replys from inbox to a NetMail
This commit is contained in:
parent
c5e3220c1d
commit
00deb3fe72
54
core/fse.js
54
core/fse.js
|
@ -411,30 +411,42 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
|
||||||
return callback(null);
|
return callback(null);
|
||||||
},
|
},
|
||||||
function populateLocalUserInfo(callback) {
|
function populateLocalUserInfo(callback) {
|
||||||
if(self.isPrivateMail()) {
|
if(!self.isPrivateMail()) {
|
||||||
self.message.setLocalFromUserId(self.client.user.userId);
|
return callback(null);
|
||||||
|
|
||||||
if(self.toUserId > 0) {
|
|
||||||
self.message.setLocalToUserId(self.toUserId);
|
|
||||||
callback(null);
|
|
||||||
} else {
|
|
||||||
// we need to look it up
|
|
||||||
User.getUserIdAndNameByLookup(self.message.toUserName, function userInfo(err, toUserId) {
|
|
||||||
if(err) {
|
|
||||||
callback(err);
|
|
||||||
} else {
|
|
||||||
self.message.setLocalToUserId(toUserId);
|
|
||||||
callback(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
callback(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// :TODO: shouldn't local from user ID be set for all mail?
|
||||||
|
self.message.setLocalFromUserId(self.client.user.userId);
|
||||||
|
|
||||||
|
if(self.toUserId > 0) {
|
||||||
|
self.message.setLocalToUserId(self.toUserId);
|
||||||
|
return callback(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// If the message we're replying to is from a remote user
|
||||||
|
// don't try to look up the local user ID. Instead, mark the mail
|
||||||
|
// for export with the remote to address.
|
||||||
|
//
|
||||||
|
if(self.replyToMessage.isFromRemoteUser()) {
|
||||||
|
self.message.setRemoteToUser(self.replyToMessage.meta.System[Message.SystemMetaNames.RemoteFromUser]);
|
||||||
|
self.message.setExternalFlavor(self.replyToMessage.meta.System[Message.SystemMetaNames.ExternalFlavor]);
|
||||||
|
return callback(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to look it up
|
||||||
|
User.getUserIdAndNameByLookup(self.message.toUserName, (err, toUserId) => {
|
||||||
|
if(err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.message.setLocalToUserId(toUserId);
|
||||||
|
return callback(null);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
function complete(err) {
|
err => {
|
||||||
cb(err, self.message);
|
return cb(err, self.message);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,10 @@ function Message(options) {
|
||||||
this.isPrivate = function() {
|
this.isPrivate = function() {
|
||||||
return Message.isPrivateAreaTag(this.areaTag);
|
return Message.isPrivateAreaTag(this.areaTag);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.isFromRemoteUser = function() {
|
||||||
|
return null !== _.get(this, 'meta.System.remote_from_user', null);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Message.WellKnownAreaTags = {
|
Message.WellKnownAreaTags = {
|
||||||
|
@ -93,6 +97,14 @@ Message.SystemMetaNames = {
|
||||||
LocalFromUserID : 'local_from_user_id',
|
LocalFromUserID : 'local_from_user_id',
|
||||||
StateFlags0 : 'state_flags0', // See Message.StateFlags0
|
StateFlags0 : 'state_flags0', // See Message.StateFlags0
|
||||||
ExplicitEncoding : 'explicit_encoding', // Explicitly set encoding when exporting/etc.
|
ExplicitEncoding : 'explicit_encoding', // Explicitly set encoding when exporting/etc.
|
||||||
|
ExternalFlavor : 'external_flavor', // "Flavor" of message - imported from or to be exported to. See Message.ExternalFlavors
|
||||||
|
RemoteToUser : 'remote_to_user', // Opaque value depends on external system, e.g. FTN address
|
||||||
|
RemoteFromUser : 'remote_from_user', // Opaque value depends on external system, e.g. FTN address
|
||||||
|
};
|
||||||
|
|
||||||
|
// Types for Message.SystemMetaNames.ExternalFlavor meta
|
||||||
|
Message.ExternalFlavors = {
|
||||||
|
FTN : 'ftn', // FTN style
|
||||||
};
|
};
|
||||||
|
|
||||||
Message.StateFlags0 = {
|
Message.StateFlags0 = {
|
||||||
|
@ -133,6 +145,16 @@ Message.prototype.setLocalFromUserId = function(userId) {
|
||||||
this.meta.System[Message.SystemMetaNames.LocalFromUserID] = userId;
|
this.meta.System[Message.SystemMetaNames.LocalFromUserID] = userId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Message.prototype.setRemoteToUser = function(remoteTo) {
|
||||||
|
this.meta.System = this.meta.System || {};
|
||||||
|
this.meta.System[Message.SystemMetaNames.RemoteToUser] = remoteTo;
|
||||||
|
};
|
||||||
|
|
||||||
|
Message.prototype.setExternalFlavor = function(flavor) {
|
||||||
|
this.meta.System = this.meta.System || {};
|
||||||
|
this.meta.System[Message.SystemMetaNames.ExternalFlavor] = flavor;
|
||||||
|
};
|
||||||
|
|
||||||
Message.createMessageUUID = function(areaTag, modTimestamp, subject, body) {
|
Message.createMessageUUID = function(areaTag, modTimestamp, subject, body) {
|
||||||
assert(_.isString(areaTag));
|
assert(_.isString(areaTag));
|
||||||
assert(_.isDate(modTimestamp) || moment.isMoment(modTimestamp));
|
assert(_.isDate(modTimestamp) || moment.isMoment(modTimestamp));
|
||||||
|
|
|
@ -170,6 +170,7 @@ exports.getModule = class NewScanModule extends MenuModule {
|
||||||
const filterCriteria = {
|
const filterCriteria = {
|
||||||
newerThanFileId : FileBaseFilters.getFileBaseLastViewedFileIdByUser(this.client.user),
|
newerThanFileId : FileBaseFilters.getFileBaseLastViewedFileIdByUser(this.client.user),
|
||||||
areaTag : getAvailableFileAreaTags(this.client),
|
areaTag : getAvailableFileAreaTags(this.client),
|
||||||
|
order : 'ascending', // oldest first
|
||||||
};
|
};
|
||||||
|
|
||||||
FileEntry.findFiles(
|
FileEntry.findFiles(
|
||||||
|
@ -179,11 +180,11 @@ exports.getModule = class NewScanModule extends MenuModule {
|
||||||
return cb(err ? err : Errors.DoesNotExist('No more new files'));
|
return cb(err ? err : Errors.DoesNotExist('No more new files'));
|
||||||
}
|
}
|
||||||
|
|
||||||
FileBaseFilters.setFileBaseLastViewedFileIdForUser( this.client.user, fileIds[0] );
|
FileBaseFilters.setFileBaseLastViewedFileIdForUser( this.client.user, fileIds[fileIds.length - 1] );
|
||||||
|
|
||||||
const menuOpts = {
|
const menuOpts = {
|
||||||
extraArgs : {
|
extraArgs : {
|
||||||
fileList : fileIds,
|
fileList : fileIds,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -90,18 +90,13 @@ function areaFix() {
|
||||||
message : messageBody,
|
message : messageBody,
|
||||||
areaTag : Message.WellKnownAreaTags.Private, // mark private
|
areaTag : Message.WellKnownAreaTags.Private, // mark private
|
||||||
meta : {
|
meta : {
|
||||||
FtnProperty : {
|
System : {
|
||||||
[ Message.FtnPropertyNames.FtnDestZone ] : ftnAddr.zone,
|
[ Message.SystemMetaNames.RemoteToUser ] : ftnAddr.toString(), // where to send it
|
||||||
[ Message.FtnPropertyNames.FtnDestNetwork ] : ftnAddr.net,
|
[ Message.SystemMetaNames.ExternalFlavor ] : Message.ExternalFlavors.FTN, // on FTN-style network
|
||||||
[ Message.FtnPropertyNames.FtnDestNode ] : ftnAddr.node,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(ftnAddr.point) {
|
|
||||||
message.meta.FtnProperty[Message.FtnPropertyNames.FtnDestPoint] = ftnAddr.point;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(0 !== fromUserId) {
|
if(0 !== fromUserId) {
|
||||||
message.setLocalFromUserId(fromUserId);
|
message.setLocalFromUserId(fromUserId);
|
||||||
}
|
}
|
||||||
|
@ -109,7 +104,6 @@ function areaFix() {
|
||||||
return callback(null, message);
|
return callback(null, message);
|
||||||
},
|
},
|
||||||
function persistMessage(message, callback) {
|
function persistMessage(message, callback) {
|
||||||
// :TODO: Persist message in private outgoing (sysop out box) (TBD: implementation)
|
|
||||||
message.persist(err => {
|
message.persist(err => {
|
||||||
if(!err) {
|
if(!err) {
|
||||||
console.log('AreaFix message persisted and will be exported at next scheduled scan');
|
console.log('AreaFix message persisted and will be exported at next scheduled scan');
|
||||||
|
|
|
@ -45,12 +45,8 @@ exports.moduleInfo = {
|
||||||
/*
|
/*
|
||||||
:TODO:
|
:TODO:
|
||||||
* Support (approx) max bundle size
|
* Support (approx) max bundle size
|
||||||
* Support NetMail
|
|
||||||
* NetMail needs explicit isNetMail() check
|
|
||||||
* NetMail filename / location / etc. is still unknown - need to post on groups & get real answers
|
|
||||||
* Validate packet passwords!!!!
|
* Validate packet passwords!!!!
|
||||||
=> secure vs insecure landing areas
|
=> secure vs insecure landing areas
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.getModule = FTNMessageScanTossModule;
|
exports.getModule = FTNMessageScanTossModule;
|
||||||
|
@ -878,12 +874,7 @@ function FTNMessageScanTossModule() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function discoverUplink(callback) {
|
function discoverUplink(callback) {
|
||||||
const dstAddr = new Address({
|
const dstAddr = new Address(message.meta.System[Message.SystemMetaNames.RemoteToUser]);
|
||||||
zone : parseInt(message.meta.FtnProperty.ftn_dest_zone),
|
|
||||||
net : parseInt(message.meta.FtnProperty.ftn_dest_network),
|
|
||||||
node : parseInt(message.meta.FtnProperty.ftn_dest_node),
|
|
||||||
point : parseInt(message.meta.FtnProperty.ftn_dest_point) || null, // point is optional
|
|
||||||
});
|
|
||||||
|
|
||||||
return self.getAcceptableNetMailNetworkInfoFromAddress(dstAddr, (err, config, routeAddress, networkName) => {
|
return self.getAcceptableNetMailNetworkInfoFromAddress(dstAddr, (err, config, routeAddress, networkName) => {
|
||||||
if(err) {
|
if(err) {
|
||||||
|
@ -1152,6 +1143,9 @@ function FTNMessageScanTossModule() {
|
||||||
function basicSetup(callback) {
|
function basicSetup(callback) {
|
||||||
message.areaTag = config.localAreaTag;
|
message.areaTag = config.localAreaTag;
|
||||||
|
|
||||||
|
// indicate this was imported from FTN
|
||||||
|
message.meta.System[Message.SystemMetaNames.ExternalFlavor] = Message.ExternalFlavors.FTN;
|
||||||
|
|
||||||
//
|
//
|
||||||
// If we *allow* dupes (disabled by default), then just generate
|
// If we *allow* dupes (disabled by default), then just generate
|
||||||
// a random UUID. Otherwise, don't assign the UUID just yet. It will be
|
// a random UUID. Otherwise, don't assign the UUID just yet. It will be
|
||||||
|
@ -1177,6 +1171,22 @@ function FTNMessageScanTossModule() {
|
||||||
return callback(null);
|
return callback(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create a meta value for the *remote* from user. In the case here with FTN,
|
||||||
|
// their fully qualified FTN from address
|
||||||
|
//
|
||||||
|
const intlKludge = _.get(message, 'meta.FtnKludge.INTL');
|
||||||
|
if(intlKludge && intlKludge.length > 0) {
|
||||||
|
let fromAddress = intlKludge.split(' ')[0];
|
||||||
|
|
||||||
|
const fromPointKludge = _.get(message, 'meta.FtnKludge.FMPT');
|
||||||
|
if(fromPointKludge) {
|
||||||
|
fromAddress += `.${fromPointKludge}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
message.meta.System[Message.SystemMetaNames.RemoteFromUser] = fromAddress;
|
||||||
|
}
|
||||||
|
|
||||||
const lookupName = self.getLocalUserNameFromAlias(message.toUserName);
|
const lookupName = self.getLocalUserNameFromAlias(message.toUserName);
|
||||||
|
|
||||||
User.getUserIdAndNameByLookup(lookupName, (err, localToUserId, localUserName) => {
|
User.getUserIdAndNameByLookup(lookupName, (err, localToUserId, localUserName) => {
|
||||||
|
@ -1911,8 +1921,7 @@ function FTNMessageScanTossModule() {
|
||||||
this.performNetMailExport = function(cb) {
|
this.performNetMailExport = function(cb) {
|
||||||
//
|
//
|
||||||
// Select all messages with a |message_id| > |lastScanId| in the private area
|
// Select all messages with a |message_id| > |lastScanId| in the private area
|
||||||
// that also *do not* have a local user ID meta value but *do* have a FTN dest
|
// that are schedule for export to FTN-style networks.
|
||||||
// network meta value.
|
|
||||||
//
|
//
|
||||||
// Just like EchoMail, we additionally exclude messages with the System state_flags0
|
// Just like EchoMail, we additionally exclude messages with the System state_flags0
|
||||||
// which will be present for imported or already exported messages
|
// which will be present for imported or already exported messages
|
||||||
|
@ -1927,12 +1936,18 @@ function FTNMessageScanTossModule() {
|
||||||
WHERE area_tag = '${Message.WellKnownAreaTags.Private}' AND message_id > ? AND
|
WHERE area_tag = '${Message.WellKnownAreaTags.Private}' AND message_id > ? AND
|
||||||
(SELECT COUNT(message_id)
|
(SELECT COUNT(message_id)
|
||||||
FROM message_meta
|
FROM message_meta
|
||||||
WHERE message_id = m.message_id AND meta_category = 'System' AND
|
WHERE message_id = m.message_id
|
||||||
(meta_name = 'state_flags0' OR meta_name='local_to_user_id')) = 0
|
AND meta_category = 'System'
|
||||||
|
AND (meta_name = 'state_flags0' OR meta_name = 'local_to_user_id')
|
||||||
|
) = 0
|
||||||
AND
|
AND
|
||||||
(SELECT COUNT(message_id)
|
(SELECT COUNT(message_id)
|
||||||
FROM message_meta
|
FROM message_meta
|
||||||
WHERE message_id = m.message_id AND meta_category='FtnProperty' AND meta_name='ftn_dest_network') = 1
|
WHERE message_id = m.message_id
|
||||||
|
AND meta_category = 'System'
|
||||||
|
AND meta_name = '${Message.SystemMetaNames.ExternalFlavor}'
|
||||||
|
AND meta_value = '${Message.ExternalFlavors.FTN}'
|
||||||
|
) = 1
|
||||||
ORDER BY message_id;
|
ORDER BY message_id;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -1967,8 +1982,8 @@ function FTNMessageScanTossModule() {
|
||||||
|
|
||||||
this.isNetMailMessage = function(message) {
|
this.isNetMailMessage = function(message) {
|
||||||
return message.isPrivate() &&
|
return message.isPrivate() &&
|
||||||
null === _.get(message.meta, 'System.LocalToUserID', null) &&
|
null === _.get(message, 'meta.System.LocalToUserID', null) &&
|
||||||
null !== _.get(message.meta, 'FtnProperty.ftn_dest_network', null)
|
Message.ExternalFlavors.FTN === _.get(message, 'meta.System.external_flavor', null)
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue