Split message consts to their own file, fix some HTTP responses, better subjects from ActivityPub messages, fix AP reply indicators, ...
This commit is contained in:
parent
0bd2c3db1c
commit
d624871a83
|
@ -171,10 +171,18 @@ module.exports = class Note extends ActivityPubObject {
|
|||
|
||||
// :TODO: it would be better to do some basic HTML to ANSI or pipe codes perhaps
|
||||
message.message = htmlToMessageBody(this.content);
|
||||
message.subject =
|
||||
this.summary ||
|
||||
truncate(message.message, { length: 32, omission: '...' }) ||
|
||||
APDefaultSummary;
|
||||
|
||||
// If the summary is not present, build one using the message itself;
|
||||
// finally, default to a static subject so there is *something* if
|
||||
// all else fails.
|
||||
if (this.summary) {
|
||||
message.subject = this.summary;
|
||||
} else {
|
||||
let subject = message.message.replace(`@${message.toUserName} `, '');
|
||||
subject = truncate(subject, { length: 32, omission: '...' });
|
||||
subject = subject || APDefaultSummary;
|
||||
message.subject = subject;
|
||||
}
|
||||
|
||||
try {
|
||||
message.modTimestamp = moment(this.published);
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
|
||||
const EnigmaAssert = require('./enigma_assert.js');
|
||||
const Address = require('./ftn_address.js');
|
||||
const { AddressFlavor } = require('./message.js');
|
||||
const Message = require('./message.js');
|
||||
const MessageConst = require('./message_const');
|
||||
const { getQuotePrefix } = require('./ftn_util');
|
||||
|
||||
exports.getAddressedToInfo = getAddressedToInfo;
|
||||
exports.setExternalAddressedToInfo = setExternalAddressedToInfo;
|
||||
exports.copyExternalAddressedToInfo = copyExternalAddressedToInfo;
|
||||
exports.getQuotePrefixFromName = getQuotePrefixFromName;
|
||||
|
||||
const EMAIL_REGEX =
|
||||
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[?[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}]?)|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
|
@ -35,29 +36,29 @@ function getAddressedToInfo(input) {
|
|||
if (firstAtPos < 0) {
|
||||
let addr = Address.fromString(input);
|
||||
if (Address.isValidAddress(addr)) {
|
||||
return { flavor: AddressFlavor.FTN, remote: input };
|
||||
return { flavor: MessageConst.AddressFlavor.FTN, remote: input };
|
||||
}
|
||||
|
||||
const lessThanPos = input.indexOf('<');
|
||||
if (lessThanPos < 0) {
|
||||
return { name: input, flavor: AddressFlavor.Local };
|
||||
return { name: input, flavor: MessageConst.AddressFlavor.Local };
|
||||
}
|
||||
|
||||
const greaterThanPos = input.indexOf('>');
|
||||
if (greaterThanPos < lessThanPos) {
|
||||
return { name: input, flavor: AddressFlavor.Local };
|
||||
return { name: input, flavor: MessageConst.AddressFlavor.Local };
|
||||
}
|
||||
|
||||
addr = Address.fromString(input.slice(lessThanPos + 1, greaterThanPos));
|
||||
if (Address.isValidAddress(addr)) {
|
||||
return {
|
||||
name: input.slice(0, lessThanPos).trim(),
|
||||
flavor: AddressFlavor.FTN,
|
||||
flavor: MessageConst.AddressFlavor.FTN,
|
||||
remote: addr.toString(),
|
||||
};
|
||||
}
|
||||
|
||||
return { name: input, flavor: AddressFlavor.Local };
|
||||
return { name: input, flavor: MessageConst.AddressFlavor.Local };
|
||||
}
|
||||
|
||||
if (firstAtPos === 0) {
|
||||
|
@ -67,7 +68,7 @@ function getAddressedToInfo(input) {
|
|||
if (m) {
|
||||
return {
|
||||
name: input.slice(1, secondAtPos),
|
||||
flavor: AddressFlavor.ActivityPub,
|
||||
flavor: MessageConst.AddressFlavor.ActivityPub,
|
||||
remote: input.slice(firstAtPos),
|
||||
};
|
||||
}
|
||||
|
@ -82,38 +83,38 @@ function getAddressedToInfo(input) {
|
|||
if (m) {
|
||||
return {
|
||||
name: input.slice(0, lessThanPos).trim(),
|
||||
flavor: AddressFlavor.Email,
|
||||
flavor: MessageConst.AddressFlavor.Email,
|
||||
remote: addr,
|
||||
};
|
||||
}
|
||||
|
||||
return { name: input, flavor: AddressFlavor.Local };
|
||||
return { name: input, flavor: MessageConst.AddressFlavor.Local };
|
||||
}
|
||||
|
||||
let m = input.match(EMAIL_REGEX);
|
||||
if (m) {
|
||||
return {
|
||||
name: input.slice(0, firstAtPos),
|
||||
flavor: AddressFlavor.Email,
|
||||
flavor: MessageConst.AddressFlavor.Email,
|
||||
remote: input,
|
||||
};
|
||||
}
|
||||
|
||||
let addr = Address.fromString(input); // 5D?
|
||||
if (Address.isValidAddress(addr)) {
|
||||
return { flavor: AddressFlavor.FTN, remote: addr.toString() };
|
||||
return { flavor: MessageConst.AddressFlavor.FTN, remote: addr.toString() };
|
||||
}
|
||||
|
||||
addr = Address.fromString(input.slice(firstAtPos + 1).trim());
|
||||
if (Address.isValidAddress(addr)) {
|
||||
return {
|
||||
name: input.slice(0, firstAtPos).trim(),
|
||||
flavor: AddressFlavor.FTN,
|
||||
flavor: MessageConst.AddressFlavor.FTN,
|
||||
remote: addr.toString(),
|
||||
};
|
||||
}
|
||||
|
||||
return { name: input, flavor: AddressFlavor.Local };
|
||||
return { name: input, flavor: MessageConst.AddressFlavor.Local };
|
||||
}
|
||||
|
||||
/// returns true if it's an external address
|
||||
|
@ -123,11 +124,11 @@ function setExternalAddressedToInfo(addressInfo, message) {
|
|||
};
|
||||
|
||||
switch (addressInfo.flavor) {
|
||||
case AddressFlavor.FTN:
|
||||
case AddressFlavor.Email:
|
||||
case AddressFlavor.QWK:
|
||||
case AddressFlavor.NNTP:
|
||||
case AddressFlavor.ActivityPub:
|
||||
case MessageConst.AddressFlavor.FTN:
|
||||
case MessageConst.AddressFlavor.Email:
|
||||
case MessageConst.AddressFlavor.QWK:
|
||||
case MessageConst.AddressFlavor.NNTP:
|
||||
case MessageConst.AddressFlavor.ActivityPub:
|
||||
EnigmaAssert(isValidAddressInfo());
|
||||
|
||||
message.setRemoteToUser(addressInfo.remote);
|
||||
|
@ -136,13 +137,18 @@ function setExternalAddressedToInfo(addressInfo, message) {
|
|||
return true;
|
||||
|
||||
default:
|
||||
case AddressFlavor.Local:
|
||||
case MessageConst.AddressFlavor.Local:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function copyExternalAddressedToInfo(fromMessage, toMessage) {
|
||||
const sm = Message.SystemMetaNames;
|
||||
const sm = MessageConst.SystemMetaNames;
|
||||
toMessage.setRemoteToUser(fromMessage.meta.System[sm.RemoteFromUser]);
|
||||
toMessage.setExternalFlavor(fromMessage.meta.System[sm.ExternalFlavor]);
|
||||
}
|
||||
|
||||
function getQuotePrefixFromName(name) {
|
||||
const addrInfo = getAddressedToInfo(name);
|
||||
return getQuotePrefix(addrInfo.name || name);
|
||||
}
|
||||
|
|
117
core/message.js
117
core/message.js
|
@ -3,14 +3,14 @@
|
|||
|
||||
const msgDb = require('./database.js').dbs.message;
|
||||
const wordWrapText = require('./word_wrap.js').wordWrapText;
|
||||
const ftnUtil = require('./ftn_util.js');
|
||||
const createNamedUUID = require('./uuid_util.js').createNamedUUID;
|
||||
const Errors = require('./enig_error.js').Errors;
|
||||
const ANSI = require('./ansi_term.js');
|
||||
const { sanitizeString, getISOTimestampString } = require('./database.js');
|
||||
|
||||
const { isCP437Encodable } = require('./cp437util');
|
||||
const { containsNonLatinCodepoints } = require('./string_util');
|
||||
const MessageConst = require('./message_const');
|
||||
const { getQuotePrefixFromName } = require('./mail_util');
|
||||
|
||||
const {
|
||||
isAnsi,
|
||||
|
@ -33,93 +33,6 @@ const ENIGMA_MESSAGE_UUID_NAMESPACE = uuidParse.parse(
|
|||
'154506df-1df8-46b9-98f8-ebb5815baaf8'
|
||||
);
|
||||
|
||||
const WELL_KNOWN_AREA_TAGS = {
|
||||
Invalid: '',
|
||||
Private: 'private_mail',
|
||||
Bulletin: 'local_bulletin',
|
||||
};
|
||||
|
||||
const WellKnownMetaCategories = {
|
||||
System: 'System',
|
||||
FtnProperty: 'FtnProperty',
|
||||
FtnKludge: 'FtnKludge',
|
||||
QwkProperty: 'QwkProperty',
|
||||
QwkKludge: 'QwkKludge',
|
||||
ActivityPub: 'ActivityPub',
|
||||
};
|
||||
|
||||
// Category: WellKnownMetaCategories.System ("System")
|
||||
const SYSTEM_META_NAMES = {
|
||||
LocalToUserID: 'local_to_user_id',
|
||||
LocalFromUserID: 'local_from_user_id',
|
||||
StateFlags0: 'state_flags0', // See Message.StateFlags0
|
||||
ExplicitEncoding: 'explicit_encoding', // Explicitly set encoding when exporting/etc.
|
||||
ExternalFlavor: 'external_flavor', // "Flavor" of message - imported from or to be exported to. See Message.AddressFlavor
|
||||
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
|
||||
const ADDRESS_FLAVOR = {
|
||||
Local: 'local', // local / non-remote addressing
|
||||
FTN: 'ftn', // FTN style
|
||||
Email: 'email', // From email
|
||||
QWK: 'qwk', // QWK packet
|
||||
NNTP: 'nntp', // NNTP article POST; often a email address
|
||||
ActivityPub: 'activitypub', // ActivityPub, Mastodon, etc.
|
||||
};
|
||||
|
||||
const STATE_FLAGS0 = {
|
||||
None: 0x00000000,
|
||||
Imported: 0x00000001, // imported from foreign system
|
||||
Exported: 0x00000002, // exported to foreign system
|
||||
};
|
||||
|
||||
// :TODO: these should really live elsewhere...
|
||||
// Category: WellKnownMetaCategories.FtnProperty ("FtnProperty")
|
||||
const FTN_PROPERTY_NAMES = {
|
||||
// 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',
|
||||
FtnCost: 'ftn_cost',
|
||||
FtnOrigZone: 'ftn_orig_zone',
|
||||
FtnDestZone: 'ftn_dest_zone',
|
||||
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
|
||||
FtnOrigin: 'ftn_origin', // http://ftsc.org/docs/fts-0004.001
|
||||
FtnArea: 'ftn_area', // http://ftsc.org/docs/fts-0004.001
|
||||
FtnSeenBy: 'ftn_seen_by', // http://ftsc.org/docs/fts-0004.001
|
||||
};
|
||||
|
||||
// Category: WellKnownMetaCategories.QwkProperty
|
||||
const QWKPropertyNames = {
|
||||
MessageNumber: 'qwk_msg_num',
|
||||
MessageStatus: 'qwk_msg_status', // See http://wiki.synchro.net/ref:qwk for a decent list
|
||||
ConferenceNumber: 'qwk_conf_num',
|
||||
InReplyToNum: 'qwk_in_reply_to_num', // note that we prefer the 'InReplyToMsgId' kludge if available
|
||||
};
|
||||
|
||||
// Category: WellKnownMetaCategories.ActivityPub
|
||||
const ActivityPubPropertyNames = {
|
||||
ActivityId: 'activitypub_activity_id', // Activity ID; FK to AP table entries
|
||||
InReplyTo: 'activitypub_in_reply_to', // Activity ID from 'inReplyTo' field
|
||||
NoteId: 'activitypub_note_id', // Note ID specific to Note Activities
|
||||
};
|
||||
|
||||
// :TODO: this is a ugly hack due to bad variable names - clean it up & just _.camelCase(k)!
|
||||
const MESSAGE_ROW_MAP = {
|
||||
reply_to_message_id: 'replyToMsgId',
|
||||
|
@ -247,35 +160,35 @@ module.exports = class Message {
|
|||
}
|
||||
|
||||
static get WellKnownMetaCategories() {
|
||||
return WellKnownMetaCategories;
|
||||
return MessageConst.WellKnownMetaCategories;
|
||||
}
|
||||
|
||||
static get WellKnownAreaTags() {
|
||||
return WELL_KNOWN_AREA_TAGS;
|
||||
return MessageConst.WellKnownAreaTags;
|
||||
}
|
||||
|
||||
static get SystemMetaNames() {
|
||||
return SYSTEM_META_NAMES;
|
||||
return MessageConst.SystemMetaNames;
|
||||
}
|
||||
|
||||
static get AddressFlavor() {
|
||||
return ADDRESS_FLAVOR;
|
||||
return MessageConst.AddressFlavor;
|
||||
}
|
||||
|
||||
static get StateFlags0() {
|
||||
return STATE_FLAGS0;
|
||||
return MessageConst.StateFlags0;
|
||||
}
|
||||
|
||||
static get FtnPropertyNames() {
|
||||
return FTN_PROPERTY_NAMES;
|
||||
return MessageConst.FtnPropertyNames;
|
||||
}
|
||||
|
||||
static get QWKPropertyNames() {
|
||||
return QWKPropertyNames;
|
||||
return MessageConst.QWKPropertyNames;
|
||||
}
|
||||
|
||||
static get ActivityPubPropertyNames() {
|
||||
return ActivityPubPropertyNames;
|
||||
return MessageConst.ActivityPubPropertyNames;
|
||||
}
|
||||
|
||||
setLocalToUserId(userId) {
|
||||
|
@ -943,11 +856,13 @@ module.exports = class Message {
|
|||
);
|
||||
}
|
||||
|
||||
// :TODO: FTN stuff doesn't have any business here
|
||||
getFTNQuotePrefix(source) {
|
||||
_getQuotePrefix(source) {
|
||||
source = source || 'fromUserName';
|
||||
|
||||
return ftnUtil.getQuotePrefix(this[source]);
|
||||
// grab out the name member, so we don't try to build
|
||||
// quote prefixes such as "@N" for "@NuSkooler@some.host", etc.
|
||||
const userName = this[source];
|
||||
return getQuotePrefixFromName(userName);
|
||||
}
|
||||
|
||||
static getTearLinePosition(input) {
|
||||
|
@ -982,7 +897,7 @@ module.exports = class Message {
|
|||
|
||||
*/
|
||||
const quotePrefix = options.includePrefix
|
||||
? this.getFTNQuotePrefix(options.prefixSource || 'fromUserName')
|
||||
? this._getQuotePrefix(options.prefixSource || 'fromUserName')
|
||||
: '';
|
||||
|
||||
function getWrapped(text, extraPrefix) {
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
const WellKnownAreaTags = {
|
||||
Invalid: '',
|
||||
Private: 'private_mail',
|
||||
Bulletin: 'local_bulletin',
|
||||
};
|
||||
exports.WellKnownAreaTags = WellKnownAreaTags;
|
||||
|
||||
const WellKnownMetaCategories = {
|
||||
System: 'System',
|
||||
FtnProperty: 'FtnProperty',
|
||||
FtnKludge: 'FtnKludge',
|
||||
QwkProperty: 'QwkProperty',
|
||||
QwkKludge: 'QwkKludge',
|
||||
ActivityPub: 'ActivityPub',
|
||||
};
|
||||
exports.WellKnownMetaCategories = WellKnownMetaCategories;
|
||||
|
||||
// Category: WellKnownMetaCategories.System ("System")
|
||||
const SystemMetaNames = {
|
||||
LocalToUserID: 'local_to_user_id',
|
||||
LocalFromUserID: 'local_from_user_id',
|
||||
StateFlags0: 'state_flags0', // See Message.StateFlags0
|
||||
ExplicitEncoding: 'explicit_encoding', // Explicitly set encoding when exporting/etc.
|
||||
ExternalFlavor: 'external_flavor', // "Flavor" of message - imported from or to be exported to. See Message.AddressFlavor
|
||||
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
|
||||
};
|
||||
exports.SystemMetaNames = SystemMetaNames;
|
||||
|
||||
// Types for Message.SystemMetaNames.ExternalFlavor meta
|
||||
const AddressFlavor = {
|
||||
Local: 'local', // local / non-remote addressing
|
||||
FTN: 'ftn', // FTN style
|
||||
Email: 'email', // From email
|
||||
QWK: 'qwk', // QWK packet
|
||||
NNTP: 'nntp', // NNTP article POST; often a email address
|
||||
ActivityPub: 'activitypub', // ActivityPub, Mastodon, etc.
|
||||
};
|
||||
exports.AddressFlavor = AddressFlavor;
|
||||
|
||||
const StateFlags0 = {
|
||||
None: 0x00000000,
|
||||
Imported: 0x00000001, // imported from foreign system
|
||||
Exported: 0x00000002, // exported to foreign system
|
||||
};
|
||||
exports.StateFlags0 = StateFlags0;
|
||||
|
||||
// Category: WellKnownMetaCategories.FtnProperty ("FtnProperty")
|
||||
const 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',
|
||||
FtnCost: 'ftn_cost',
|
||||
FtnOrigZone: 'ftn_orig_zone',
|
||||
FtnDestZone: 'ftn_dest_zone',
|
||||
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
|
||||
FtnOrigin: 'ftn_origin', // http://ftsc.org/docs/fts-0004.001
|
||||
FtnArea: 'ftn_area', // http://ftsc.org/docs/fts-0004.001
|
||||
FtnSeenBy: 'ftn_seen_by', // http://ftsc.org/docs/fts-0004.001
|
||||
};
|
||||
exports.FtnPropertyNames = FtnPropertyNames;
|
||||
|
||||
// Category: WellKnownMetaCategories.QwkProperty
|
||||
const QWKPropertyNames = {
|
||||
MessageNumber: 'qwk_msg_num',
|
||||
MessageStatus: 'qwk_msg_status', // See http://wiki.synchro.net/ref:qwk for a decent list
|
||||
ConferenceNumber: 'qwk_conf_num',
|
||||
InReplyToNum: 'qwk_in_reply_to_num', // note that we prefer the 'InReplyToMsgId' kludge if available
|
||||
};
|
||||
exports.QWKPropertyNames = QWKPropertyNames;
|
||||
|
||||
// Category: WellKnownMetaCategories.ActivityPub
|
||||
const ActivityPubPropertyNames = {
|
||||
ActivityId: 'activitypub_activity_id', // Activity ID; FK to AP table entries
|
||||
InReplyTo: 'activitypub_in_reply_to', // Activity ID from 'inReplyTo' field
|
||||
NoteId: 'activitypub_note_id', // Note ID specific to Note Activities
|
||||
};
|
||||
exports.ActivityPubPropertyNames = ActivityPubPropertyNames;
|
|
@ -258,7 +258,7 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
|||
{ type: activity.type },
|
||||
'Invalid or unknown Activity type'
|
||||
);
|
||||
return this.resourceNotFound(resp);
|
||||
return this.webServer.resourceNotFound(resp);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -279,7 +279,7 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
|||
{ type: createWhat },
|
||||
'Invalid or unsupported "Create" type'
|
||||
);
|
||||
return this.resourceNotFound(resp);
|
||||
return this.webServer.resourceNotFound(resp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue