From a8e867a4bb343796416515c0c19d4370875d5b1c Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Sat, 4 Feb 2023 11:51:47 -0700 Subject: [PATCH] Support 'maxLength' property in MLTEV; Enforce this by default, to 500 characters for AP messages. WIP optional subjects, some new configuration --- .../activitypub_user_config_main.ans | Bin 3171 -> 3177 bytes core/activitypub/activity.js | 1 + core/config_default.js | 12 +++++++++ core/fse.js | 21 +++++++++++++--- core/mail_util.js | 23 ++++++++++++++++++ core/multi_line_edit_text_view.js | 20 +++++++++++++++ core/view.js | 2 +- core/wfc.js | 3 ++- 8 files changed, 76 insertions(+), 6 deletions(-) diff --git a/art/themes/luciano_blocktronics/activitypub_user_config_main.ans b/art/themes/luciano_blocktronics/activitypub_user_config_main.ans index a0d31ac370c603aa610cbdd72609824a3b2a8a4c..bd591ead34eb4a3c384ac3200cef33a9c46366ce 100644 GIT binary patch delta 45 zcmaDX@ls;L2{tZcb88c`T-6X?!^w)=>XSIdHuJE*VP-Nm-~64+m66H#|71HJRRB-R B4d4I( delta 24 gcmaDU@mONR3AW9r*$h}V|KoCDWHS6Y*@Z_H0EOELX8-^I diff --git a/core/activitypub/activity.js b/core/activitypub/activity.js index 07a25e14..d5db4112 100644 --- a/core/activitypub/activity.js +++ b/core/activitypub/activity.js @@ -94,6 +94,7 @@ module.exports = class Activity extends ActivityPubObject { return postJson(actorUrl, activityJson, reqOpts, cb); } + // :TODO: we need dp/support a bit more here... recipientIds() { const ids = []; diff --git a/core/config_default.js b/core/config_default.js index 87b586c2..a50d78b7 100644 --- a/core/config_default.js +++ b/core/config_default.js @@ -413,6 +413,18 @@ module.exports = () => { }, }, + // General ActivityPub integration configuration + activityPub: { + // Mimics Mastodon max 500 characters for *outgoing* Notes + // (messages destined for ActivityPub); This is a soft limit; + // Implementations including Mastodon should still display + // longer messages, but this keeps us as a "good citizen" + autoSignatures: false, + + // by default, don't include auto-signatures in AP outgoing + maxMessageLength: 500, + }, + infoExtractUtils: { Exiftool2Desc: { cmd: `${__dirname}/../util/exiftool2desc.js`, // ensure chmod +x diff --git a/core/fse.js b/core/fse.js index fd0f6aac..f7d39d07 100644 --- a/core/fse.js +++ b/core/fse.js @@ -18,6 +18,7 @@ const { stripMciColorCodes, controlCodesToAnsi } = require('./color_codes.js'); const Config = require('./config.js').get; const { getAddressedToInfo, + messageInfoFromAddressedToInfo, setExternalAddressedToInfo, copyExternalAddressedToInfo, } = require('./mail_util.js'); @@ -424,10 +425,15 @@ exports.FullScreenEditorModule = // // Append auto-signature, if enabled for the area & the user has one // - if (false != area.autoSignatures) { - const sig = this.client.user.getProperty(UserProps.AutoSignature); - if (sig) { - messageBody += `\r\n-- \r\n${sig}`; + const msgInfo = messageInfoFromAddressedToInfo( + getAddressedToInfo(headerValues.to) + ); + if (false !== msgInfo.autoSignatures) { + if (false !== area.autoSignatures) { + const sig = this.client.user.getProperty(UserProps.AutoSignature); + if (sig) { + messageBody += `\r\n-- \r\n${sig}`; + } } } @@ -1391,6 +1397,13 @@ exports.FullScreenEditorModule = } switchToBody() { + const to = this.getView('header', MciViewIds.header.to).getData(); + const msgInfo = messageInfoFromAddressedToInfo(getAddressedToInfo(to)); + if (msgInfo.maxMessageLength > 0) { + const bodyView = this.getView('body', MciViewIds.body.message); + bodyView.maxLength = msgInfo.maxMessageLength; + } + this.viewControllers.header.setFocus(false); this.viewControllers.body.switchFocus(1); diff --git a/core/mail_util.js b/core/mail_util.js index 3ab6bb9f..aba0771f 100644 --- a/core/mail_util.js +++ b/core/mail_util.js @@ -5,10 +5,15 @@ const EnigmaAssert = require('./enigma_assert.js'); const Address = require('./ftn_address.js'); const MessageConst = require('./message_const'); const { getQuotePrefix } = require('./ftn_util'); +const Config = require('./config').get; + +// deps +const { get } = require('lodash'); exports.getAddressedToInfo = getAddressedToInfo; exports.setExternalAddressedToInfo = setExternalAddressedToInfo; exports.copyExternalAddressedToInfo = copyExternalAddressedToInfo; +exports.messageInfoFromAddressedToInfo = messageInfoFromAddressedToInfo; exports.getQuotePrefixFromName = getQuotePrefixFromName; const EMAIL_REGEX = @@ -148,6 +153,24 @@ function copyExternalAddressedToInfo(fromMessage, toMessage) { toMessage.setExternalFlavor(fromMessage.meta.System[sm.ExternalFlavor]); } +function messageInfoFromAddressedToInfo(addressInfo) { + switch (addressInfo.flavor) { + case MessageConst.AddressFlavor.ActivityPub: { + const config = Config(); + const maxMessageLength = get(config, 'activityPub.maxMessageLength', 500); + const autoSignatures = get(config, 'activityPub.autoSignatures', false); + + // Additionally, it's ot necessary to supply a subject + // (aka summary) with a 'Note' Activity + return { subjectOptional: true, maxMessageLength, autoSignatures }; + } + + default: + // autoSignatures: null = varies by additional config + return { subjectOptional: false, maxMessageLength: 0, autoSignatures: null }; + } +} + function getQuotePrefixFromName(name) { const addrInfo = getAddressedToInfo(name); return getQuotePrefix(addrInfo.name || name); diff --git a/core/multi_line_edit_text_view.js b/core/multi_line_edit_text_view.js index 025f14d4..5fddbb1b 100644 --- a/core/multi_line_edit_text_view.js +++ b/core/multi_line_edit_text_view.js @@ -113,6 +113,7 @@ function MultiLineEditTextView(options) { this.textLines = []; this.topVisibleIndex = 0; this.mode = options.mode || 'edit'; // edit | preview | read-only + this.maxLength = 0; // no max by default if ('preview' === this.mode) { this.autoScroll = options.autoScroll || true; @@ -317,6 +318,15 @@ function MultiLineEditTextView(options) { return text; }; + this.getCharacterLength = function () { + // :TODO: FSE needs re-write anyway, but this should just be known all the time vs calc. Too much of a mess right now... + let len = 0; + this.textLines.forEach(tl => { + len += tl.text.length; + }); + return len; + }; + this.replaceCharacterInText = function (c, index, col) { self.textLines[index].text = strUtil.replaceAt( self.textLines[index].text, @@ -664,6 +674,10 @@ function MultiLineEditTextView(options) { }; this.keyPressCharacter = function (c) { + if (this.maxLength > 0 && this.getCharacterLength() + 1 >= this.maxLength) { + return; + } + var index = self.getTextLinesIndex(); // @@ -1170,6 +1184,12 @@ MultiLineEditTextView.prototype.setPropertyValue = function (propName, value) { this.specialKeyMap.next = this.specialKeyMap.next || []; this.specialKeyMap.next.push('tab'); break; + + case 'maxLength': + if (_.isNumber(value)) { + this.maxLength = value; + } + break; } MultiLineEditTextView.super_.prototype.setPropertyValue.call(this, propName, value); diff --git a/core/view.js b/core/view.js index fe0c4a88..ed8f08d0 100644 --- a/core/view.js +++ b/core/view.js @@ -150,7 +150,7 @@ View.prototype.setPosition = function (pos) { this.position.col = parseInt(arguments[1], 10); } - // sanatize + // sanitize this.position.row = Math.max(this.position.row, 1); this.position.col = Math.max(this.position.col, 1); this.position.row = Math.min(this.position.row, this.client.term.termHeight); diff --git a/core/wfc.js b/core/wfc.js index 3f127424..13ef6cde 100644 --- a/core/wfc.js +++ b/core/wfc.js @@ -226,6 +226,7 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { enter() { this.client.stopIdleMonitor(); this._applyOpVisibility(); + Events.on( Events.getSystemEvents().ClientDisconnected, this._clientDisconnected.bind(this) @@ -240,7 +241,7 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { Events.removeListener( Events.getSystemEvents().ClientDisconnected, - this._clientDisconnected + this._clientDisconnected.bind(this) ); this._restoreOpVisibility();