diff --git a/CHANGES.md b/CHANGES.md index 609306610..08e2b3b77 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,6 +15,7 @@ - #1306 added option `notification_delay` - #1312 Error `unrecognized expression` in Safari - #1316 show version info in login dialog +- #1317 Don't show errors for CSI messages - #1318 added values 'on' and 'off' for 'trusted' option which removes the "This is a trusted device" checkbox from the login form - #1319 Implement sending of presences according to XEP-0319: Last User Interaction in Presence diff --git a/dist/converse.js b/dist/converse.js index ba78980a3..5d3856eb4 100644 --- a/dist/converse.js +++ b/dist/converse.js @@ -71131,6 +71131,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha */ if (_converse.send_chat_state_notifications && this.get('chat_state')) { _converse.api.send($msg({ + 'id': _converse.connection.getUniqueId(), 'to': this.get('jid'), 'type': 'chat' }).c(this.get('chat_state'), { @@ -71395,6 +71396,27 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha return true; } + const id = message.getAttribute('id'); + + if (id) { + const msg = chatbox.messages.findWhere({ + 'msgid': id + }); + + if (!msg) { + // This error refers to a message not included in our store. + // We assume that this was a CSI message (which we don't store). + // See https://github.com/conversejs/converse.js/issues/1317 + return; + } + } else { + // An error message without id likely means that we + // sent a message without id (which shouldn't happen). + _converse.log('Received an error message without id attribute!', Strophe.LogLevel.ERROR); + + _converse.log(message, Strophe.LogLevel.ERROR); + } + chatbox.createMessage(message, message); return true; }, diff --git a/spec/messages.js b/spec/messages.js index 5a18f6411..163aad72b 100644 --- a/spec/messages.js +++ b/spec/messages.js @@ -1620,6 +1620,44 @@ expect(chat_content.querySelectorAll('.chat-error').length).toEqual(3); done(); })); + + it("will not show to the user an error message for a CSI message", + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + async function (done, _converse) { + + // See #1317 + // https://github.com/conversejs/converse.js/issues/1317 + test_utils.createContacts(_converse, 'current'); + _converse.emit('rosterContactsFetched'); + test_utils.openControlBox(); + + const contact_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost'; + await test_utils.openChatBoxFor(_converse, contact_jid); + + const messages = _converse.connection.sent_stanzas.filter(s => s.nodeName === 'message'); + expect(messages.length).toBe(1); + expect(Strophe.serialize(messages[0])).toBe( + ``+ + ``+ + ``+ + ``+ + ``); + + const stanza = $msg({ + 'from': contact_jid, + 'type': 'error', + 'id': messages[0].getAttribute('id') + }).c('error', {'type': 'cancel', 'code': '503'}) + .c('service-unavailable', { 'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas' }).up() + .c('text', { 'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas' }) + .t('User session not found') + _converse.connection._dataRecv(test_utils.createRequest(stanza)); + const view = _converse.chatboxviews.get(contact_jid); + const chat_content = view.el.querySelector('.chat-content'); + expect(chat_content.querySelectorAll('.chat-error').length).toEqual(0); + done(); + })); }); diff --git a/src/converse-message-view.js b/src/converse-message-view.js index 8cd942206..16e1cae10 100644 --- a/src/converse-message-view.js +++ b/src/converse-message-view.js @@ -168,10 +168,10 @@ converse.plugins.add('converse-message-view', { renderErrorMessage () { const moment_time = moment(this.model.get('time')), msg = u.stringToElement( - tpl_info(_.extend(this.model.toJSON(), { - 'extra_classes': 'chat-error', - 'isodate': moment_time.format() - }))); + tpl_info(_.extend(this.model.toJSON(), { + 'extra_classes': 'chat-error', + 'isodate': moment_time.format() + }))); return this.replaceElement(msg); }, diff --git a/src/headless/converse-chatboxes.js b/src/headless/converse-chatboxes.js index cf69d0db7..987e15900 100644 --- a/src/headless/converse-chatboxes.js +++ b/src/headless/converse-chatboxes.js @@ -427,10 +427,13 @@ converse.plugins.add('converse-chatboxes', { */ if (_converse.send_chat_state_notifications && this.get('chat_state')) { _converse.api.send( - $msg({'to':this.get('jid'), 'type': 'chat'}) - .c(this.get('chat_state'), {'xmlns': Strophe.NS.CHATSTATES}).up() - .c('no-store', {'xmlns': Strophe.NS.HINTS}).up() - .c('no-permanent-store', {'xmlns': Strophe.NS.HINTS}) + $msg({ + 'id': _converse.connection.getUniqueId(), + 'to': this.get('jid'), + 'type': 'chat' + }).c(this.get('chat_state'), {'xmlns': Strophe.NS.CHATSTATES}).up() + .c('no-store', {'xmlns': Strophe.NS.HINTS}).up() + .c('no-permanent-store', {'xmlns': Strophe.NS.HINTS}) ); } }, @@ -666,6 +669,21 @@ converse.plugins.add('converse-chatboxes', { if (!chatbox) { return true; } + const id = message.getAttribute('id'); + if (id) { + const msg = chatbox.messages.findWhere({'msgid': id}); + if (!msg) { + // This error refers to a message not included in our store. + // We assume that this was a CSI message (which we don't store). + // See https://github.com/conversejs/converse.js/issues/1317 + return; + } + } else { + // An error message without id likely means that we + // sent a message without id (which shouldn't happen). + _converse.log('Received an error message without id attribute!', Strophe.LogLevel.ERROR); + _converse.log(message, Strophe.LogLevel.ERROR); + } chatbox.createMessage(message, message); return true; }, diff --git a/tests/mock.js b/tests/mock.js index 191fabfe7..5ff6a2c03 100644 --- a/tests/mock.js +++ b/tests/mock.js @@ -111,17 +111,29 @@ mock.mock_connection = function () { // eslint-disable-line wrap-iife return function () { Strophe.Bosh.prototype._processRequest = function () {}; // Don't attempt to send out stanzas - var c = new Strophe.Connection('jasmine tests'); - var sendIQ = c.sendIQ; + const c = new Strophe.Connection('jasmine tests'); + const sendIQ = c.sendIQ; c.IQ_stanzas = []; c.IQ_ids = []; c.sendIQ = function (iq, callback, errback) { this.IQ_stanzas.push(iq); - var id = sendIQ.bind(this)(iq, callback, errback); + const id = sendIQ.bind(this)(iq, callback, errback); this.IQ_ids.push(id); return id; } + + const send = c.send; + c.sent_stanzas = []; + c.send = function (stanza) { + if (_.isElement(stanza)) { + this.sent_stanzas.push(stanza); + } else { + this.sent_stanzas.push(stanza.nodeTree); + } + return send.apply(this, arguments); + } + c.features = Strophe.xmlHtmlNode( ''+ ''+