diff --git a/dist/converse.js b/dist/converse.js index d0b3e6594..582ad444a 100644 --- a/dist/converse.js +++ b/dist/converse.js @@ -61982,6 +61982,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha const archive = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, original_stanza).pop(), spoiler = sizzle(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`, original_stanza).pop(), delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop(), + stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop(), chat_state = stanza.getElementsByTagName(_converse.COMPOSING).length && _converse.COMPOSING || stanza.getElementsByTagName(_converse.PAUSED).length && _converse.PAUSED || stanza.getElementsByTagName(_converse.INACTIVE).length && _converse.INACTIVE || stanza.getElementsByTagName(_converse.ACTIVE).length && _converse.ACTIVE || stanza.getElementsByTagName(_converse.GONE).length && _converse.GONE; const attrs = { @@ -61992,6 +61993,8 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha 'message': _converse.chatboxes.getMessageBody(stanza) || undefined, 'msgid': stanza.getAttribute('id'), 'references': this.getReferencesFromStanza(stanza), + 'stanza_id': stanza_id ? stanza_id.getAttribute('id') : undefined, + 'stanza_id_by_jid': stanza_id ? stanza_id.getAttribute('by') : undefined, 'subject': _.propertyOf(stanza.querySelector('subject'))('textContent'), 'thread': _.propertyOf(stanza.querySelector('thread'))('textContent'), 'time': delay ? delay.getAttribute('stamp') : moment().format(), @@ -65219,13 +65222,6 @@ function getMessageArchiveID(stanza) { if (!_.isUndefined(result)) { return result.getAttribute('id'); - } // See: https://xmpp.org/extensions/xep-0313.html#archives_id - - - const stanza_id = sizzle__WEBPACK_IMPORTED_MODULE_3___default()(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop(); - - if (!_.isUndefined(stanza_id)) { - return stanza_id.getAttribute('id'); } } @@ -66942,27 +66938,25 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc return data; }, - isDuplicate(message, original_stanza) { - // XXX: original_stanza is not used here, but in converse-mam - const msgid = message.getAttribute('id'), - jid = message.getAttribute('from'); + async isDuplicate(message, original_stanza) { + const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, message).pop(); - if (msgid) { - const msg = this.messages.findWhere({ - 'msgid': msgid, - 'from': jid - }); - - if (msg && msg.get('sender') === 'me' && !msg.get('received')) { - msg.save({ - 'received': moment().format() - }); - } - - return msg; + if (!stanza_id) { + return; } - return false; + const by_jid = stanza_id.getAttribute('by'); + const result = await _converse.api.disco.supports(Strophe.NS.SID, by_jid); + + if (!result.length) { + return false; + } + + const msg = this.messages.findWhere({ + 'stanza_id': stanza_id.getAttribute('id'), + 'stanza_id_by_jid': by_jid + }); + return !_.isNil(msg); }, fetchFeaturesIfConfigurationChanged(stanza) { @@ -67067,7 +67061,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc stanza = forwarded.querySelector('message'); } - if (this.isDuplicate(stanza, original_stanza)) { + if (await this.isDuplicate(stanza, original_stanza)) { return; } diff --git a/spec/messages.js b/spec/messages.js index 6211d5a66..2c50dcf13 100644 --- a/spec/messages.js +++ b/spec/messages.js @@ -2172,7 +2172,6 @@ done(); })); - it("can not be expected to have a unique id attribute", mock.initConverse( null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, @@ -2204,6 +2203,62 @@ done(); })); + it("is ignored if it has the same stanza-id of an already received on", + mock.initConverse( + null, ['rosterGroupsFetched'], {}, + async function (done, _converse) { + + const features = [ + 'http://jabber.org/protocol/muc', + 'jabber:iq:register', + 'muc_passwordprotected', + 'muc_hidden', + 'muc_temporary', + 'muc_membersonly', + 'muc_unmoderated', + 'muc_nonanonymous', + Strophe.NS.SID, + ]; + await test_utils.openAndEnterChatRoom(_converse, 'room', 'muc.example.com', 'dummy', features); + const view = _converse.chatboxviews.get('room@muc.example.com'); + spyOn(view.model, 'isDuplicate').and.callThrough(); + let stanza = u.toStanza(` + + Typical body text + + + `); + _converse.connection._dataRecv(test_utils.createRequest(stanza)); + await test_utils.waitUntil(() => _converse.api.chats.get().length); + await test_utils.waitUntil(() => view.model.messages.length === 1); + await test_utils.waitUntil(() => view.model.isDuplicate.calls.count() === 1); + let result = await view.model.isDuplicate.calls.all()[0].returnValue; + expect(result).toBe(false); + + stanza = u.toStanza(` + + Typical body text + + + `); + _converse.connection._dataRecv(test_utils.createRequest(stanza)); + await test_utils.waitUntil(() => view.model.isDuplicate.calls.count() === 2); + result = await view.model.isDuplicate.calls.all()[1].returnValue; + expect(result).toBe(true); + expect(view.model.messages.length).toBe(1); + done(); + })); + it("keeps track whether you are the sender or not", mock.initConverse( null, ['rosterGroupsFetched'], {}, diff --git a/src/headless/converse-chatboxes.js b/src/headless/converse-chatboxes.js index 89f94c9e1..454e4716b 100644 --- a/src/headless/converse-chatboxes.js +++ b/src/headless/converse-chatboxes.js @@ -596,6 +596,7 @@ converse.plugins.add('converse-chatboxes', { const archive = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, original_stanza).pop(), spoiler = sizzle(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`, original_stanza).pop(), delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop(), + stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop(), chat_state = stanza.getElementsByTagName(_converse.COMPOSING).length && _converse.COMPOSING || stanza.getElementsByTagName(_converse.PAUSED).length && _converse.PAUSED || stanza.getElementsByTagName(_converse.INACTIVE).length && _converse.INACTIVE || @@ -610,6 +611,8 @@ converse.plugins.add('converse-chatboxes', { 'message': _converse.chatboxes.getMessageBody(stanza) || undefined, 'msgid': stanza.getAttribute('id'), 'references': this.getReferencesFromStanza(stanza), + 'stanza_id': stanza_id ? stanza_id.getAttribute('id') : undefined, + 'stanza_id_by_jid': stanza_id ? stanza_id.getAttribute('by') : undefined, 'subject': _.propertyOf(stanza.querySelector('subject'))('textContent'), 'thread': _.propertyOf(stanza.querySelector('thread'))('textContent'), 'time': delay ? delay.getAttribute('stamp') : moment().format(), diff --git a/src/headless/converse-mam.js b/src/headless/converse-mam.js index e3b1b8671..1878144a1 100644 --- a/src/headless/converse-mam.js +++ b/src/headless/converse-mam.js @@ -32,11 +32,6 @@ function getMessageArchiveID (stanza) { if (!_.isUndefined(result)) { return result.getAttribute('id'); } - // See: https://xmpp.org/extensions/xep-0313.html#archives_id - const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop(); - if (!_.isUndefined(stanza_id)) { - return stanza_id.getAttribute('id'); - } } function queryForArchivedMessages (_converse, options, callback, errback) { diff --git a/src/headless/converse-muc.js b/src/headless/converse-muc.js index a2c4d6f00..3db64b1f5 100644 --- a/src/headless/converse-muc.js +++ b/src/headless/converse-muc.js @@ -948,20 +948,21 @@ converse.plugins.add('converse-muc', { return data; }, - isDuplicate (message, original_stanza) { - // XXX: original_stanza is not used here, but in converse-mam - const msgid = message.getAttribute('id'), - jid = message.getAttribute('from'); - - if (msgid) { - const msg = this.messages.findWhere({'msgid': msgid, 'from': jid}); - if (msg && msg.get('sender') === 'me' && !msg.get('received')) { - msg.save({'received': moment().format()}); - } - return msg; + async isDuplicate (message, original_stanza) { + const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, message).pop(); + if (!stanza_id) { + return false; } - return false; - + const by_jid = stanza_id.getAttribute('by'); + const result = await _converse.api.disco.supports(Strophe.NS.SID, by_jid); + if (!result.length) { + return false; + } + const msg = this.messages.findWhere({ + 'stanza_id': stanza_id.getAttribute('id'), + 'stanza_id_by_jid': by_jid + }); + return !_.isNil(msg); }, fetchFeaturesIfConfigurationChanged (stanza) { @@ -1055,7 +1056,7 @@ converse.plugins.add('converse-muc', { if (forwarded) { stanza = forwarded.querySelector('message'); } - if (this.isDuplicate(stanza, original_stanza)) { + if (await this.isDuplicate(stanza, original_stanza)) { return; } const attrs = await this.getMessageAttributesFromStanza(stanza, original_stanza);