Explorar o código

Also create MEP messages received from a MAM archive

JC Brand %!s(int64=3) %!d(string=hai) anos
pai
achega
8f34065fc0

+ 3 - 1
src/headless/plugins/chat/utils.js

@@ -28,7 +28,9 @@ async function handleErrorMessage (stanza) {
         return;
     }
     const chatbox = await api.chatboxes.get(from_jid);
-    chatbox?.handleErrorMessageStanza(stanza);
+    if (chatbox.get('type') === _converse.PRIVATE_CHAT_TYPE) {
+        chatbox?.handleErrorMessageStanza(stanza);
+    }
 }
 
 export function autoJoinChats () {

+ 53 - 14
src/headless/plugins/muc/muc.js

@@ -434,6 +434,7 @@ const ChatRoomMixin = {
         if (!(await this.shouldShowErrorMessage(attrs))) {
             return;
         }
+
         const message = this.getMessageReferencedByError(attrs);
         if (message) {
             const new_attrs = {
@@ -535,19 +536,22 @@ const ChatRoomMixin = {
      * @param { XMLElement } stanza
      */
     async handleMessageStanza (stanza) {
-        if (stanza.getAttribute('type') !== 'groupchat') {
-            this.handleForwardedMentions(stanza);
-            return;
-        } else if (isArchived(stanza)) {
-            // MAM messages are handled in converse-mam.
-            // We shouldn't get MAM messages here because
-            // they shouldn't have a `type` attribute.
-            return log.warn(`Received a MAM message with type "groupchat"`);
+        const type = stanza.getAttribute('type');
+        if (type === 'error') {
+            return this.handleErrorMessageStanza(stanza);
+        }
+        if (type === 'groupchat') {
+            if (isArchived(stanza)) {
+                // MAM messages are handled in converse-mam.
+                // We shouldn't get MAM messages here because
+                // they shouldn't have a `type` attribute.
+                return log.warn(`Received a MAM message with type "groupchat"`);
+            }
+            this.createInfoMessages(stanza);
+            this.fetchFeaturesIfConfigurationChanged(stanza);
+        } else if (!type) {
+            return this.handleForwardedMentions(stanza);
         }
-
-        this.createInfoMessages(stanza);
-        this.fetchFeaturesIfConfigurationChanged(stanza);
-
         /**
          * @typedef { Object } MUCMessageData
          * An object containing the original groupchat message stanza,
@@ -2098,11 +2102,43 @@ const ChatRoomMixin = {
         return false;
     },
 
+    /**
+     * Given { @link MessageAttributes } look for XEP-0316 Room Notifications and create info
+     * messages for them.
+     * @param { XMLElement } stanza
+     */
+    handleMEPNotification (attrs) {
+        if (attrs.from !== this.get('jid') || !attrs.activities) {
+            return false;
+        }
+        attrs.activities?.forEach(activity_attrs => {
+            const mdata = Object.assign({ 'msgid': attrs.msgid }, activity_attrs);
+            this.createMessage(mdata)
+        });
+        return !!attrs.activities.length
+    },
+
+    /**
+     * Returns an already cached message (if it exists) based on the
+     * passed in attributes map.
+     * @method _converse.ChatRoom#getDuplicateMessage
+     * @param { object } attrs - Attributes representing a received
+     *  message, as returned by { @link parseMUCMessage }
+     * @returns {Promise<_converse.Message>}
+     */
+    getDuplicateMessage (attrs) {
+        if (attrs.activities?.length) {
+            return this.messages.findWhere({'type': 'info', 'msgid': attrs.msgid});
+        } else {
+            return _converse.ChatBox.prototype.getDuplicateMessage.call(this, attrs);
+        }
+    },
+
+
     /**
      * Handler for all MUC messages sent to this groupchat. This method
      * shouldn't be called directly, instead {@link _converse.ChatRoom#queueMessage}
      * should be called.
-     * @private
      * @method _converse.ChatRoom#onMessage
      * @param { MessageAttributes } attrs - A promise which resolves to the message attributes.
      */
@@ -2114,13 +2150,15 @@ const ChatRoomMixin = {
         }
         const message = this.getDuplicateMessage(attrs);
         if (message) {
-            return this.updateMessage(message, attrs);
+            (message.get('type') === 'groupchat') && this.updateMessage(message, attrs);
+            return;
         } else if (attrs.is_valid_receipt_request || attrs.is_marker || this.ignorableCSN(attrs)) {
             return;
         }
 
         if (
             this.handleMetadataFastening(attrs) ||
+            this.handleMEPNotification(attrs) ||
             (await this.handleRetraction(attrs)) ||
             (await this.handleModeration(attrs)) ||
             (await this.handleSubjectChange(attrs))
@@ -2128,6 +2166,7 @@ const ChatRoomMixin = {
             attrs.nick && this.removeNotification(attrs.nick, ['composing', 'paused']);
             return;
         }
+
         this.setEditable(attrs, attrs.time);
 
         if (attrs['chat_state']) {

+ 3 - 1
src/headless/plugins/muc/parsers.js

@@ -33,7 +33,7 @@ const { NS } = Strophe;
 export function getMEPActivities (stanza) {
     const items_el = sizzle(`items[node="${Strophe.NS.CONFINFO}"]`, stanza).pop();
     if (!items_el) {
-        return [];
+        return null;
     }
     const from = stanza.getAttribute('from');
     const msgid = stanza.getAttribute('id');
@@ -127,6 +127,7 @@ export async function parseMUCMessage (stanza, chatbox, _converse) {
      * @typedef { Object } MUCMessageAttributes
      * The object which {@link parseMUCMessage} returns
      * @property { ('me'|'them') } sender - Whether the message was sent by the current user or someone else
+     * @property { Array<Object> } activities - A list of objects representing XEP-0316 MEP notification data
      * @property { Array<Object> } references - A list of objects representing XEP-0372 references
      * @property { Boolean } editable - Is this message editable via XEP-0308?
      * @property { Boolean } is_archived -  Is this message from a XEP-0313 MAM archive?
@@ -181,6 +182,7 @@ export async function parseMUCMessage (stanza, chatbox, _converse) {
         {
             from,
             nick,
+            'activities': getMEPActivities(stanza),
             'body': stanza.querySelector('body')?.textContent?.trim(),
             'chat_state': getChatState(stanza),
             'from_muc': Strophe.getBareJidFromJid(from),

+ 0 - 52
src/headless/plugins/muc/utils.js

@@ -2,7 +2,6 @@ import isObject from 'lodash-es/isObject';
 import log from "@converse/headless/log.js";
 import { ROLES } from '@converse/headless/plugins/muc/index.js';
 import { _converse, api, converse } from '@converse/headless/core.js';
-import { getMEPActivities } from '@converse/headless/plugins/muc/parsers.js';
 import { safeSave } from '@converse/headless/utils/core.js';
 
 const { Strophe, sizzle, u } = converse.env;
@@ -180,57 +179,6 @@ export async function autoJoinRooms () {
 }
 
 
-/**
- * Given a stanza, look for XEP-0316 Room Notifications and create info
- * messages for them.
- * @param { XMLElement } stanza
- */
-async function handleMEPNotification (stanza) {
-    const from = stanza.getAttribute('from');
-    if (u.isSameBareJID(from, _converse.bare_jid)) {
-        return;
-    }
-    const room = await api.rooms.get(from);
-    if (!room) {
-        log.warn(`Received a MEP message for a non-existent room: ${from}`);
-        return;
-    }
-    const msgid = stanza.getAttribute('id');
-    if (room.messages.findWhere({ msgid })) {
-        // We already handled this stanza before
-        return;
-    }
-    getMEPActivities(stanza, room).forEach(attrs => {
-        room.createMessage(attrs);
-        api.trigger('message', { stanza, attrs, 'chatbox': room });
-    });
-}
-
-
-function checkIfMEP (message) {
-    try {
-        if (sizzle(`event[xmlns="${Strophe.NS.PUBSUB}#event"]`, message).length) {
-            handleMEPNotification(message);
-        }
-    } catch (e) {
-        log.error(e.message);
-    }
-    return true;
-}
-
-
-export function registerPEPPushHandler () {
-    // Add a handler for devices pushed from other connected clients
-    _converse.connection.addHandler(checkIfMEP, null, 'message', 'headline');
-
-    // XXX: This is a hack. Prosody's MUC MAM doesn't allow for quering
-    // non-groupchat messages. So even though they might be archived, they
-    // don't get returned on query. To bypass this, some MEP messages are sent
-    // with type="groupchat".
-    // https://hg.prosody.im/prosody-modules/rev/da9469e68dee
-    _converse.connection.addHandler(checkIfMEP, null, 'message', 'groupchat');
-}
-
 export function onAddClientFeatures () {
     if (api.settings.get('allow_muc')) {
         api.disco.own.features.add(Strophe.NS.MUC);

+ 2 - 9
src/plugins/muc-views/tests/retractions.js

@@ -576,7 +576,6 @@ describe("Message Retractions", function () {
             occupant.save('role', 'member');
             const retraction_stanza = await sendAndThenRetractMessage(_converse, view);
             await u.waitUntil(() => view.querySelectorAll('.chat-msg--retracted').length === 1, 1000);
-            console.log('XXX: First message retracted by author');
 
             const msg_obj = view.model.messages.last();
             expect(msg_obj.get('retracted')).toBeTruthy();
@@ -598,19 +597,15 @@ describe("Message Retractions", function () {
             const reflection = u.toStanza(`
                 <message type="groupchat" id="${retraction_stanza.getAttribute('id')}" from="${muc_jid}" to="${muc_jid}/romeo">
                     <apply-to id="${stanza_id}" xmlns="urn:xmpp:fasten:0">
-                        <moderated by='${_converse.bare_jid}' xmlns='urn:xmpp:message-moderate:0'>
-                            <retract xmlns='urn:xmpp:message-retract:0' />
-                        </moderated>
+                        <retract xmlns='urn:xmpp:message-retract:0' />
                     </apply-to>
                 </message>`);
 
             spyOn(view.model, 'handleRetraction').and.callThrough();
             _converse.connection._dataRecv(mock.createRequest(reflection));
             await u.waitUntil(() => view.model.handleRetraction.calls.count() === 1, 1000);
-            console.log('XXX: Handle retraction was called on reflection');
 
-            await u.waitUntil(() => view.model.messages.length === 1, 1000);
-            console.log('XXX: We have one message');
+            await u.waitUntil(() => view.model.messages.length === 2, 1000);
             expect(view.model.messages.last().get('retracted')).toBeTruthy();
             expect(view.model.messages.last().get('is_ephemeral')).toBe(false);
             expect(view.model.messages.last().get('editable')).toBe(false);
@@ -648,9 +643,7 @@ describe("Message Retractions", function () {
                         <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
                     </error>
                     <apply-to id="${stanza_id}" xmlns="urn:xmpp:fasten:0">
-                        <moderated by='${_converse.bare_jid}' xmlns='urn:xmpp:message-moderate:0'>
                         <retract xmlns='urn:xmpp:message-retract:0' />
-                        </moderated>
                     </apply-to>
                 </message>`);