Commit 33600eee authored by JC Brand's avatar JC Brand

No need for a separate `archive_id` value.

With MAM2 we can just use stanza-id
parent be6a5d9c
...@@ -61911,6 +61911,9 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha ...@@ -61911,6 +61911,9 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
return this.vcard.get('fullname') || this.get('jid'); return this.vcard.get('fullname') || this.get('jid');
}, },
updateMessage(message, stanza) {// Overridden in converse-muc and converse-mam
},
handleMessageCorrection(stanza) { handleMessageCorrection(stanza) {
const replace = sizzle(`replace[xmlns="${Strophe.NS.MESSAGE_CORRECT}"]`, stanza).pop(); const replace = sizzle(`replace[xmlns="${Strophe.NS.MESSAGE_CORRECT}"]`, stanza).pop();
...@@ -61942,11 +61945,15 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha ...@@ -61942,11 +61945,15 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
return false; return false;
}, },
getDuplicateMessage(stanza) {
return this.findDuplicateFromOriginID(stanza) || this.findDuplicateFromStanzaID(stanza);
},
findDuplicateFromOriginID(stanza) { findDuplicateFromOriginID(stanza) {
const origin_id = sizzle(`origin-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop(); const origin_id = sizzle(`origin-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
if (!origin_id) { if (!origin_id) {
return false; return null;
} }
return this.messages.findWhere({ return this.messages.findWhere({
...@@ -61955,27 +61962,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha ...@@ -61955,27 +61962,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
}); });
}, },
async hasDuplicateArchiveID(stanza) { async findDuplicateFromStanzaID(stanza) {
const result = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, stanza).pop();
if (!result) {
return false;
}
const by_jid = stanza.getAttribute('from') || this.get('jid');
const supported = await _converse.api.disco.supports(Strophe.NS.MAM, by_jid);
if (!supported.length) {
return false;
}
const query = {};
query[`stanza_id ${by_jid}`] = result.getAttribute('id');
const msg = this.messages.findWhere(query);
return !_.isNil(msg);
},
async hasDuplicateStanzaID(stanza) {
const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop(); const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
if (!stanza_id) { if (!stanza_id) {
...@@ -61991,8 +61978,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha ...@@ -61991,8 +61978,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
const query = {}; const query = {};
query[`stanza_id ${by_jid}`] = stanza_id.getAttribute('id'); query[`stanza_id ${by_jid}`] = stanza_id.getAttribute('id');
const msg = this.messages.findWhere(query); return this.messages.findWhere(query);
return !_.isNil(msg);
}, },
sendMarker(to_jid, id, type) { sendMarker(to_jid, id, type) {
...@@ -62349,6 +62335,10 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha ...@@ -62349,6 +62335,10 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
return attrs; return attrs;
}, },
isArchived(original_stanza) {
return !_.isNil(sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, original_stanza).pop());
},
getMessageAttributesFromStanza(stanza, original_stanza) { getMessageAttributesFromStanza(stanza, original_stanza) {
/* Parses a passed in message stanza and returns an object /* Parses a passed in message stanza and returns an object
* of attributes. * of attributes.
...@@ -62361,15 +62351,14 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha ...@@ -62361,15 +62351,14 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
* that contains the message stanza, if it was * that contains the message stanza, if it was
* contained, otherwise it's the message stanza itself. * contained, otherwise it's the message stanza itself.
*/ */
const archive = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, original_stanza).pop(), const spoiler = sizzle(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`, original_stanza).pop(),
spoiler = sizzle(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`, original_stanza).pop(),
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop(), delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop(),
text = _converse.chatboxes.getMessageBody(stanza) || undefined, text = _converse.chatboxes.getMessageBody(stanza) || undefined,
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; 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 = _.extend({ const attrs = _.extend({
'chat_state': chat_state, 'chat_state': chat_state,
'is_archived': !_.isNil(archive), 'is_archived': this.isArchived(original_stanza),
'is_delayed': !_.isNil(delay), 'is_delayed': !_.isNil(delay),
'is_spoiler': !_.isNil(spoiler), 'is_spoiler': !_.isNil(spoiler),
'is_single_emoji': text ? u.isSingleEmoji(text) : false, 'is_single_emoji': text ? u.isSingleEmoji(text) : false,
...@@ -62637,12 +62626,20 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha ...@@ -62637,12 +62626,20 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
'nickname': roster_nick 'nickname': roster_nick
}, has_body); }, has_body);
if (chatbox && !chatbox.findDuplicateFromOriginID(stanza) && !(await chatbox.hasDuplicateArchiveID(original_stanza)) && !(await chatbox.hasDuplicateStanzaID(stanza)) && !chatbox.handleMessageCorrection(stanza) && !chatbox.handleReceipt(stanza, from_jid, is_carbon, is_me) && !chatbox.handleChatMarker(stanza, from_jid, is_carbon, is_roster_contact)) { if (chatbox) {
const attrs = await chatbox.getMessageAttributesFromStanza(stanza, original_stanza); const message = await chatbox.getDuplicateMessage(stanza);
if (attrs['chat_state'] || !u.isEmptyMessage(attrs)) { if (message) {
const msg = chatbox.messages.create(attrs); chatbox.updateMessage(message, original_stanza);
chatbox.incrementUnreadMsgCounter(msg); }
if (!message && !chatbox.handleMessageCorrection(stanza) && !chatbox.handleReceipt(stanza, from_jid, is_carbon, is_me) && !chatbox.handleChatMarker(stanza, from_jid, is_carbon, is_roster_contact)) {
const attrs = await chatbox.getMessageAttributesFromStanza(stanza, original_stanza);
if (attrs['chat_state'] || !u.isEmptyMessage(attrs)) {
const msg = chatbox.messages.create(attrs);
chatbox.incrementUnreadMsgCounter(msg);
}
} }
} }
...@@ -65603,18 +65600,6 @@ const RSM_ATTRIBUTES = ['max', 'first', 'last', 'after', 'before', 'index', 'cou ...@@ -65603,18 +65600,6 @@ const RSM_ATTRIBUTES = ['max', 'first', 'last', 'after', 'before', 'index', 'cou
const MAM_ATTRIBUTES = ['with', 'start', 'end']; const MAM_ATTRIBUTES = ['with', 'start', 'end'];
function getMessageArchiveID(stanza) {
// See https://xmpp.org/extensions/xep-0313.html#results
//
// The result messages MUST contain a <result/> element with an 'id'
// attribute that gives the current message's archive UID
const result = sizzle__WEBPACK_IMPORTED_MODULE_3___default()(`result[xmlns="${Strophe.NS.MAM}"]`, stanza).pop();
if (!_.isUndefined(result)) {
return result.getAttribute('id');
}
}
function queryForArchivedMessages(_converse, options, callback, errback) { function queryForArchivedMessages(_converse, options, callback, errback) {
/* Internal function, called by the "archive.query" API method. /* Internal function, called by the "archive.query" API method.
*/ */
...@@ -65739,10 +65724,44 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-mam ...@@ -65739,10 +65724,44 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-mam
// //
// New functions which don't exist yet can also be added. // New functions which don't exist yet can also be added.
ChatBox: { ChatBox: {
async getMessageAttributesFromStanza(message, original_stanza) { async findDuplicateFromArchiveID(stanza) {
const attrs = await this.__super__.getMessageAttributesFromStanza.apply(this, arguments); const _converse = this.__super__._converse;
attrs.archive_id = getMessageArchiveID(original_stanza); const result = sizzle__WEBPACK_IMPORTED_MODULE_3___default()(`result[xmlns="${Strophe.NS.MAM}"]`, stanza).pop();
return attrs;
if (!result) {
return null;
}
const by_jid = stanza.getAttribute('from') || this.get('jid');
const supported = await _converse.api.disco.supports(Strophe.NS.MAM, by_jid);
if (!supported.length) {
return null;
}
const query = {};
query[`stanza_id ${by_jid}`] = result.getAttribute('id');
return this.messages.findWhere(query);
},
async getDuplicateMessage(stanza) {
const message = await this.__super__.getDuplicateMessage.apply(this, arguments);
if (!message) {
return this.findDuplicateFromArchiveID(stanza);
}
return message;
},
updateMessage(message, stanza) {
this.__super__.updateMessage.apply(this, arguments);
if (message && !message.get('is_archived')) {
message.save(_.extend({
'is_archived': this.isArchived(stanza)
}, this.getStanzaIDs(stanza)));
}
} }
}, },
...@@ -65771,11 +65790,11 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-mam ...@@ -65771,11 +65790,11 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-mam
if (_.isNil(most_recent_msg)) { if (_.isNil(most_recent_msg)) {
this.fetchArchivedMessages(); this.fetchArchivedMessages();
} else { } else {
const archive_id = most_recent_msg.get('archive_id'); const stanza_id = most_recent_msg.get(`stanza_id ${this.model.get('jid')}`);
if (archive_id) { if (stanza_id) {
this.fetchArchivedMessages({ this.fetchArchivedMessages({
'after': most_recent_msg.get('archive_id') 'after': stanza_id
}); });
} else { } else {
this.fetchArchivedMessages({ this.fetchArchivedMessages({
...@@ -65874,11 +65893,12 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-mam ...@@ -65874,11 +65893,12 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-mam
if (this.content.scrollTop === 0 && this.model.messages.length) { if (this.content.scrollTop === 0 && this.model.messages.length) {
const oldest_message = this.model.messages.at(0); const oldest_message = this.model.messages.at(0);
const archive_id = oldest_message.get('archive_id'); const by_jid = this.model.get('jid');
const stanza_id = oldest_message.get(`stanza_id ${by_jid}`);
if (archive_id) { if (stanza_id) {
this.fetchArchivedMessages({ this.fetchArchivedMessages({
'before': archive_id 'before': stanza_id
}); });
} else { } else {
this.fetchArchivedMessages({ this.fetchArchivedMessages({
...@@ -65888,24 +65908,6 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-mam ...@@ -65888,24 +65908,6 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-mam
} }
} }
},
ChatRoom: {
isDuplicate(message, original_stanza) {
const result = this.__super__.isDuplicate.apply(this, arguments);
if (result) {
return result;
}
const archive_id = getMessageArchiveID(original_stanza);
if (archive_id) {
return this.messages.filter({
'archive_id': archive_id
}).length > 0;
}
}
}, },
ChatRoomView: { ChatRoomView: {
initialize() { initialize() {
...@@ -67350,39 +67352,6 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc ...@@ -67350,39 +67352,6 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc
acknowledged[xmlns="${Strophe.NS.MARKERS}"]`, stanza).length > 0; acknowledged[xmlns="${Strophe.NS.MARKERS}"]`, stanza).length > 0;
}, },
handleReflection(stanza) {
/* Handle a MUC reflected message and return true if so.
*
* Parameters:
* (XMLElement) stanza: The message stanza
*/
const from = stanza.getAttribute('from');
const own_message = Strophe.getResourceFromJid(from) == this.get('nick');
if (own_message) {
const msg = this.findDuplicateFromOriginID(stanza);
if (msg) {
const attrs = {};
const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
const by_jid = stanza_id ? stanza_id.getAttribute('by') : undefined;
if (by_jid) {
const key = `stanza_id ${by_jid}`;
attrs[key] = stanza_id.getAttribute('id');
}
if (!msg.get('received')) {
attrs.received = moment().format();
}
msg.save(attrs);
}
return msg ? true : false;
}
},
subjectChangeHandled(attrs) { subjectChangeHandled(attrs) {
/* Handle a subject change and return `true` if so. /* Handle a subject change and return `true` if so.
* *
...@@ -67419,6 +67388,33 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc ...@@ -67419,6 +67388,33 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc
return is_csn && (attrs.is_delayed || own_message); return is_csn && (attrs.is_delayed || own_message);
}, },
updateMessage(message, stanza) {
/* Make sure that the already cached message is updated with
* the stanza ID.
*/
_converse.ChatBox.prototype.updateMessage.call(this, message, stanza);
const from = stanza.getAttribute('from');
const own_message = Strophe.getResourceFromJid(from) == this.get('nick');
if (own_message) {
const attrs = {};
const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
const by_jid = stanza_id ? stanza_id.getAttribute('by') : undefined;
if (by_jid) {
const key = `stanza_id ${by_jid}`;
attrs[key] = stanza_id.getAttribute('id');
}
if (!message.get('received')) {
attrs.received = moment().format();
}
message.save(attrs);
}
},
async onMessage(stanza) { async onMessage(stanza) {
/* Handler for all MUC messages sent to this groupchat. /* Handler for all MUC messages sent to this groupchat.
* *
...@@ -67433,7 +67429,13 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc ...@@ -67433,7 +67429,13 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc
stanza = forwarded.querySelector('message'); stanza = forwarded.querySelector('message');
} }
if (this.handleReflection(stanza) || (await this.hasDuplicateArchiveID(original_stanza)) || (await this.hasDuplicateStanzaID(stanza)) || this.handleMessageCorrection(stanza) || this.isReceipt(stanza) || this.isChatMarker(stanza)) { const message = await this.getDuplicateMessage(original_stanza);
if (message) {
this.updateMessage(message, original_stanza);
}
if (message || this.handleMessageCorrection(stanza) || this.isReceipt(stanza) || this.isChatMarker(stanza)) {
return _converse.emit('message', { return _converse.emit('message', {
'stanza': original_stanza 'stanza': original_stanza
}); });
...@@ -14,96 +14,147 @@ ...@@ -14,96 +14,147 @@
describe("Message Archive Management", function () { describe("Message Archive Management", function () {
// Implement the protocol defined in https://xmpp.org/extensions/xep-0313.html#config // Implement the protocol defined in https://xmpp.org/extensions/xep-0313.html#config
describe("Archived Messages", function () { describe("An archived message", function () {
it("aren't shown as duplicates by comparing their stanza id and archive id", describe("when recieved", function () {
mock.initConverse(
null, ['discoInitialized'], {}, it("updates the is_archived value of an already cached version",
async function (done, _converse) { mock.initConverse(
null, ['discoInitialized'], {},
await test_utils.openAndEnterChatRoom(_converse, 'trek-radio', 'conference.lightwitch.org', 'jcbrand'); async function (done, _converse) {
const view = _converse.chatboxviews.get('trek-radio@conference.lightwitch.org');
let stanza = u.toStanza( await test_utils.openAndEnterChatRoom(_converse, 'trek-radio', 'conference.lightwitch.org', 'dummy');
`<message xmlns="jabber:client" to="jcbrand@lightwitch.org/converse.js-73057452" type="groupchat" from="trek-radio@conference.lightwitch.org/comndrdukath#0805 (STO)">
<body>negan</body> const view = _converse.chatboxviews.get('trek-radio@conference.lightwitch.org');
<stanza-id xmlns="urn:xmpp:sid:0" id="45fbbf2a-1059-479d-9283-c8effaf05621" by="trek-radio@conference.lightwitch.org"/> let stanza = u.toStanza(
</message>`); `<message xmlns="jabber:client" to="dummy@localhost/resource" type="groupchat" from="trek-radio@conference.lightwitch.org/some1">
_converse.connection._dataRecv(test_utils.createRequest(stanza)); <body>Hello</body>
await test_utils.waitUntil(() => view.content.querySelectorAll('.chat-msg').length); <stanza-id xmlns="urn:xmpp:sid:0" id="45fbbf2a-1059-479d-9283-c8effaf05621" by="trek-radio@conference.lightwitch.org"/>
// Not sure whether such a race-condition might pose a problem </message>`);
// in "real-world" situations. _converse.connection._dataRecv(test_utils.createRequest(stanza));
stanza = u.toStanza( await test_utils.waitUntil(() => view.content.querySelectorAll('.chat-msg').length);
`<message xmlns="jabber:client" expect(view.model.messages.length).toBe(1);
to="jcbrand@lightwitch.org/converse.js-73057452" expect(view.model.messages.at(0).get('is_archived')).toBe(false);
from="trek-radio@conference.lightwitch.org"> expect(view.model.messages.at(0).get('stanza_id trek-radio@conference.lightwitch.org')).toBe('45fbbf2a-1059-479d-9283-c8effaf05621');
<result xmlns="urn:xmpp:mam:2" queryid="82d9db27-6cf8-4787-8c2c-5a560263d823" id="45fbbf2a-1059-479d-9283-c8effaf05621">
<forwarded xmlns="urn:xmpp:forward:0"> stanza = u.toStanza(
<delay xmlns="urn:xmpp:delay" stamp="2018-01-09T06:17:23Z"/> `<message xmlns="jabber:client"
<message from="trek-radio@conference.lightwitch.org/comndrdukath#0805 (STO)" type="groupchat"> to="dummy@localhost/resource"
<body>negan</body> from="trek-radio@conference.lightwitch.org">
</message> <result xmlns="urn:xmpp:mam:2" queryid="82d9db27-6cf8-4787-8c2c-5a560263d823" id="45fbbf2a-1059-479d-9283-c8effaf05621">
</forwarded> <forwarded xmlns="urn:xmpp:forward:0">
</result> <delay xmlns="urn:xmpp:delay" stamp="2018-01-09T06:17:23Z"/>
</message>`); <message from="trek-radio@conference.lightwitch.org/some1" type="groupchat">
spyOn(view.model, 'hasDuplicateArchiveID').and.callThrough(); <body>Hello</body>
view.model.onMessage(stanza); </message>
await test_utils.waitUntil(() => view.model.hasDuplicateArchiveID.calls.count()); </forwarded>
expect(view.model.hasDuplicateArchiveID.calls.count()).toBe(1); </result>
const result = await view.model.hasDuplicateArchiveID.calls.all()[0].returnValue </message>`);
expect(result).toBe(true); spyOn(view.model, 'findDuplicateFromArchiveID').and.callThrough();
expect(view.content.querySelectorAll('.chat-msg').length).toBe(1); spyOn(view.model, 'updateMessage').and.callThrough();
done(); view.model.onMessage(stanza);
})); await test_utils.waitUntil(() => view.model.findDuplicateFromArchiveID.calls.count());
expect(view.model.findDuplicateFromArchiveID.calls.count()).toBe(1);
it("aren't shown as duplicates by comparing only their archive id", const result = await view.model.findDuplicateFromArchiveID.calls.all()[0].returnValue
mock.initConverse( expect(result instanceof _converse.Message).toBe(true);
null, ['discoInitialized'], {}, expect(view.content.querySelectorAll('.chat-msg').length).toBe(1);
async function (done, _converse) {
await test_utils.waitUntil(() => view.model.updateMessage.calls.count());
await test_utils.openAndEnterChatRoom(_converse, 'discuss', 'conference.conversejs.org', 'dummy'); expect(view.model.messages.length).toBe(1);
const view = _converse.chatboxviews.get('discuss@conference.conversejs.org'); expect(view.model.messages.at(0).get('is_archived')).toBe(true);
let stanza = u.toStanza( expect(view.model.messages.at(0).get('stanza_id trek-radio@conference.lightwitch.org')).toBe('45fbbf2a-1059-479d-9283-c8effaf05621');
`<message xmlns="jabber:client" to="dummy@localhost/resource" from="discuss@conference.conversejs.org"> done();
<result xmlns="urn:xmpp:mam:2" queryid="06fea9ca-97c9-48c4-8583-009ff54ea2e8" id="7a9fde91-4387-4bf8-b5d3-978dab8f6bf3"> }));
<forwarded xmlns="urn:xmpp:forward:0">
<delay xmlns="urn:xmpp:delay" stamp="2018-12-05T04:53:12Z"/> it("isn't shown as duplicate by comparing its stanza id or archive id",
<message xmlns="jabber:client" to="discuss@conference.conversejs.org" type="groupchat" xml:lang="en" from="discuss@conference.conversejs.org/prezel"> mock.initConverse(
<body>looks like omemo fails completely with "bundle is undefined" when there is a device in the devicelist that has no keys published</body> null, ['discoInitialized'], {},
<x xmlns="http://jabber.org/protocol/muc#user"> async function (done, _converse) {
<item affiliation="none" jid="prezel@blubber.im" role="participant"/>
</x> await test_utils.openAndEnterChatRoom(_converse, 'trek-radio', 'conference.lightwitch.org', 'jcbrand');
</message> const view = _converse.chatboxviews.get('trek-radio@conference.lightwitch.org');
</forwarded> let stanza = u.toStanza(
</result> `<message xmlns="jabber:client" to="jcbrand@lightwitch.org/converse.js-73057452" type="groupchat" from="trek-radio@conference.lightwitch.org/comndrdukath#0805 (STO)">
</message>`); <body>negan</body>
view.model.onMessage(stanza); <stanza-id xmlns="urn:xmpp:sid:0" id="45fbbf2a-1059-479d-9283-c8effaf05621" by="trek-radio@conference.lightwitch.org"/>
await test_utils.waitUntil(() => view.content.querySelectorAll('.chat-msg').length); </message>`);
expect(view.content.querySelectorAll('.chat-msg').length).toBe(1); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => view.content.querySelectorAll('.chat-msg').length);
stanza = u.toStanza( // Not sure whether such a race-condition might pose a problem
`<message xmlns="jabber:client" to="dummy@localhost/resource" from="discuss@conference.conversejs.org"> // in "real-world" situations.
<result xmlns="urn:xmpp:mam:2" queryid="06fea9ca-97c9-48c4-8583-009ff54ea2e8" id="7a9fde91-4387-4bf8-b5d3-978dab8f6bf3"> stanza = u.toStanza(
<forwarded xmlns="urn:xmpp:forward:0"> `<message xmlns="jabber:client"
<delay xmlns="urn:xmpp:delay" stamp="2018-12-05T04:53:12Z"/> to="jcbrand@lightwitch.org/converse.js-73057452"
<message xmlns="jabber:client" to="discuss@conference.conversejs.org" type="groupchat" xml:lang="en" from="discuss@conference.conversejs.org/prezel"> from="trek-radio@conference.lightwitch.org">
<body>looks like omemo fails completely with "bundle is undefined" when there is a device in the devicelist that has no keys published</body> <result xmlns="urn:xmpp:mam:2" queryid="82d9db27-6cf8-4787-8c2c-5a560263d823" id="45fbbf2a-1059-479d-9283-c8effaf05621">
<x xmlns="http://jabber.org/protocol/muc#user"> <forwarded xmlns="urn:xmpp:forward:0">
<item affiliation="none" jid="prezel@blubber.im" role="participant"/> <delay xmlns="urn:xmpp:delay" stamp="2018-01-09T06:17:23Z"/>
</x> <message from="trek-radio@conference.lightwitch.org/comndrdukath#0805 (STO)" type="groupchat">
</message> <body>negan</body>
</forwarded> </message>
</result> </forwarded>
</message>`); </result>
</message>`);
spyOn(view.model, 'hasDuplicateArchiveID').and.callThrough(); spyOn(view.model, 'findDuplicateFromArchiveID').and.callThrough();
view.model.onMessage(stanza); view.model.onMessage(stanza);
await test_utils.waitUntil(() => view.model.hasDuplicateArchiveID.calls.count()); await test_utils.waitUntil(() => view.model.findDuplicateFromArchiveID.calls.count());
expect(view.model.hasDuplicateArchiveID.calls.count()).toBe(1); expect(view.model.findDuplicateFromArchiveID.calls.count()).toBe(1);
const result = await view.model.hasDuplicateArchiveID.calls.all()[0].returnValue const result = await view.model.findDuplicateFromArchiveID.calls.all()[0].returnValue
expect(result).toBe(true); expect(result instanceof _converse.Message).toBe(true);
expect(view.content.querySelectorAll('.chat-msg').length).toBe(1); expect(view.content.querySelectorAll('.chat-msg').length).toBe(1);
done(); done();
})) }));
it("isn't shown as duplicate by comparing only the archive id",
mock.initConverse(
null, ['discoInitialized'], {},
async function (done, _converse) {
await test_utils.openAndEnterChatRoom(_converse, 'discuss', 'conference.conversejs.org', 'dummy');
const view = _converse.chatboxviews.get('discuss@conference.conversejs.org');
let stanza = u.toStanza(
`<message xmlns="jabber:client" to="dummy@localhost/resource" from="discuss@conference.conversejs.org">
<result xmlns="urn:xmpp:mam:2" queryid="06fea9ca-97c9-48c4-8583-009ff54ea2e8" id="7a9fde91-4387-4bf8-b5d3-978dab8f6bf3">
<forwarded xmlns="urn:xmpp:forward:0">
<delay xmlns="urn:xmpp:delay" stamp="2018-12-05T04:53:12Z"/>
<message xmlns="jabber:client" to="discuss@conference.conversejs.org" type="groupchat" xml:lang="en" from="discuss@conference.conversejs.org/prezel">
<body>looks like omemo fails completely with "bundle is undefined" when there is a device in the devicelist that has no keys published</body>
<x xmlns="http://jabber.org/protocol/muc#user">
<item affiliation="none" jid="prezel@blubber.im" role="participant"/>
</x>
</message>
</forwarded>
</result>
</message>`);
view.model.onMessage(stanza);
await test_utils.waitUntil(() => view.content.querySelectorAll('.chat-msg').length);
expect(view.content.querySelectorAll('.chat-msg').length).toBe(1);
stanza = u.toStanza(
`<message xmlns="jabber:client" to="dummy@localhost/resource" from="discuss@conference.conversejs.org">
<result xmlns="urn:xmpp:mam:2" queryid="06fea9ca-97c9-48c4-8583-009ff54ea2e8" id="7a9fde91-4387-4bf8-b5d3-978dab8f6bf3">
<forwarded xmlns="urn:xmpp:forward:0">
<delay xmlns="urn:xmpp:delay" stamp="2018-12-05T04:53:12Z"/>
<message xmlns="jabber:client" to="discuss@conference.conversejs.org" type="groupchat" xml:lang="en" from="discuss@conference.conversejs.org/prezel">
<body>looks like omemo fails completely with "bundle is undefined" when there is a device in the devicelist that has no keys published</body>
<x xmlns="http://jabber.org/protocol/muc#user">
<item affiliation="none" jid="prezel@blubber.im" role="participant"/>
</x>
</message>
</forwarded>
</result>
</message>`);
spyOn(view.model, 'findDuplicateFromArchiveID').and.callThrough();
view.model.onMessage(stanza);
await test_utils.waitUntil(() => view.model.findDuplicateFromArchiveID.calls.count());
expect(view.model.findDuplicateFromArchiveID.calls.count()).toBe(1);
const result = await view.model.findDuplicateFromArchiveID.calls.all()[0].returnValue
expect(result instanceof _converse.Message).toBe(true);
expect(view.content.querySelectorAll('.chat-msg').length).toBe(1);
done();
}))
});
}); });
describe("The archive.query API", function () { describe("The archive.query API", function () {
......
...@@ -2223,7 +2223,7 @@ ...@@ -2223,7 +2223,7 @@
await test_utils.openAndEnterChatRoom(_converse, 'room', 'muc.example.com', 'dummy'); await test_utils.openAndEnterChatRoom(_converse, 'room', 'muc.example.com', 'dummy');
const view = _converse.chatboxviews.get('room@muc.example.com'); const view = _converse.chatboxviews.get('room@muc.example.com');
spyOn(view.model, 'hasDuplicateStanzaID').and.callThrough(); spyOn(view.model, 'findDuplicateFromStanzaID').and.callThrough();
let stanza = u.toStanza(` let stanza = u.toStanza(`
<message xmlns="jabber:client" <message xmlns="jabber:client"
from="room@muc.example.com/some1" from="room@muc.example.com/some1"
...@@ -2238,9 +2238,9 @@ ...@@ -2238,9 +2238,9 @@
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => _converse.api.chats.get().length); await test_utils.waitUntil(() => _converse.api.chats.get().length);
await test_utils.waitUntil(() => view.model.messages.length === 1); await test_utils.waitUntil(() => view.model.messages.length === 1);
await test_utils.waitUntil(() => view.model.hasDuplicateStanzaID.calls.count() === 1); await test_utils.waitUntil(() => view.model.findDuplicateFromStanzaID.calls.count() === 1);
let result = await view.model.hasDuplicateStanzaID.calls.all()[0].returnValue; let result = await view.model.findDuplicateFromStanzaID.calls.all()[0].returnValue;
expect(result).toBe(false); expect(result).toBe(undefined);
stanza = u.toStanza(` stanza = u.toStanza(`
<message xmlns="jabber:client" <message xmlns="jabber:client"
...@@ -2254,9 +2254,9 @@ ...@@ -2254,9 +2254,9 @@
<origin-id xmlns="urn:xmpp:sid:0" id="de305d54-75b4-431b-adb2-eb6b9e546013"/> <origin-id xmlns="urn:xmpp:sid:0" id="de305d54-75b4-431b-adb2-eb6b9e546013"/>
</message>`); </message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => view.model.hasDuplicateStanzaID.calls.count() === 2); await test_utils.waitUntil(() => view.model.findDuplicateFromStanzaID.calls.count() === 2);
result = await view.model.hasDuplicateStanzaID.calls.all()[1].returnValue; result = await view.model.findDuplicateFromStanzaID.calls.all()[1].returnValue;
expect(result).toBe(true); expect(result instanceof _converse.Message).toBe(true);
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(1);
done(); done();
})); }));
...@@ -2477,7 +2477,13 @@ ...@@ -2477,7 +2477,13 @@
<origin-id xmlns="urn:xmpp:sid:0" id="${msg_obj.get('origin_id')}"/> <origin-id xmlns="urn:xmpp:sid:0" id="${msg_obj.get('origin_id')}"/>
</message>`); </message>`);
await view.model.onMessage(stanza); await view.model.onMessage(stanza);
await test_utils.waitUntil(() => view.el.querySelectorAll('.chat-msg__receipt').length);
expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(1); expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(1);
expect(view.model.messages.length).toBe(1);
const message = view.model.messages.at(0);
expect(message.get('stanza_id lounge@localhost')).toBe('5f3dbc5e-e1d3-4077-a492-693f3769c7ad');
expect(message.get('origin_id')).toBe(msg_obj.get('origin_id'));
done(); done();
})); }));
...@@ -2518,9 +2524,9 @@ ...@@ -2518,9 +2524,9 @@
by="room@muc.example.com"/> by="room@muc.example.com"/>
<origin-id xmlns="urn:xmpp:sid:0" id="${attrs.origin_id}"/> <origin-id xmlns="urn:xmpp:sid:0" id="${attrs.origin_id}"/>
</message>`); </message>`);
spyOn(view.model, 'handleReflection').and.callThrough(); spyOn(view.model, 'updateMessage').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => view.model.handleReflection.calls.count() === 1); await test_utils.waitUntil(() => view.model.updateMessage.calls.count() === 1);
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(1);
expect(view.model.messages.at(0).get('stanza_id room@muc.example.com')).toBe("5f3dbc5e-e1d3-4077-a492-693f3769c7ad"); expect(view.model.messages.at(0).get('stanza_id room@muc.example.com')).toBe("5f3dbc5e-e1d3-4077-a492-693f3769c7ad");
expect(view.model.messages.at(0).get('origin_id')).toBe(attrs.origin_id); expect(view.model.messages.at(0).get('origin_id')).toBe(attrs.origin_id);
......
...@@ -290,6 +290,10 @@ converse.plugins.add('converse-chatboxes', { ...@@ -290,6 +290,10 @@ converse.plugins.add('converse-chatboxes', {
return this.vcard.get('fullname') || this.get('jid'); return this.vcard.get('fullname') || this.get('jid');
}, },
updateMessage (message, stanza) {
// Overridden in converse-muc and converse-mam
},
handleMessageCorrection (stanza) { handleMessageCorrection (stanza) {
const replace = sizzle(`replace[xmlns="${Strophe.NS.MESSAGE_CORRECT}"]`, stanza).pop(); const replace = sizzle(`replace[xmlns="${Strophe.NS.MESSAGE_CORRECT}"]`, stanza).pop();
if (replace) { if (replace) {
...@@ -316,10 +320,14 @@ converse.plugins.add('converse-chatboxes', { ...@@ -316,10 +320,14 @@ converse.plugins.add('converse-chatboxes', {
return false; return false;
}, },
getDuplicateMessage (stanza) {
return this.findDuplicateFromOriginID(stanza) || this.findDuplicateFromStanzaID(stanza);
},
findDuplicateFromOriginID (stanza) { findDuplicateFromOriginID (stanza) {
const origin_id = sizzle(`origin-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop(); const origin_id = sizzle(`origin-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
if (!origin_id) { if (!origin_id) {
return false; return null;
} }
return this.messages.findWhere({ return this.messages.findWhere({
'origin_id': origin_id.getAttribute('id'), 'origin_id': origin_id.getAttribute('id'),
...@@ -327,23 +335,7 @@ converse.plugins.add('converse-chatboxes', { ...@@ -327,23 +335,7 @@ converse.plugins.add('converse-chatboxes', {
}); });
}, },
async hasDuplicateArchiveID (stanza) { async findDuplicateFromStanzaID(stanza) {
const result = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, stanza).pop();
if (!result) {
return false;
}
const by_jid = stanza.getAttribute('from') || this.get('jid');
const supported = await _converse.api.disco.supports(Strophe.NS.MAM, by_jid);
if (!supported.length) {
return false;
}
const query = {};
query[`stanza_id ${by_jid}`] = result.getAttribute('id');
const msg = this.messages.findWhere(query);
return !_.isNil(msg);
},
async hasDuplicateStanzaID (stanza) {
const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop(); const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
if (!stanza_id) { if (!stanza_id) {
return false; return false;
...@@ -355,8 +347,7 @@ converse.plugins.add('converse-chatboxes', { ...@@ -355,8 +347,7 @@ converse.plugins.add('converse-chatboxes', {
} }
const query = {}; const query = {};
query[`stanza_id ${by_jid}`] = stanza_id.getAttribute('id'); query[`stanza_id ${by_jid}`] = stanza_id.getAttribute('id');
const msg = this.messages.findWhere(query); return this.messages.findWhere(query);
return !_.isNil(msg);
}, },
...@@ -654,6 +645,10 @@ converse.plugins.add('converse-chatboxes', { ...@@ -654,6 +645,10 @@ converse.plugins.add('converse-chatboxes', {
return attrs; return attrs;
}, },
isArchived (original_stanza) {
return !_.isNil(sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, original_stanza).pop());
},
getMessageAttributesFromStanza (stanza, original_stanza) { getMessageAttributesFromStanza (stanza, original_stanza) {
/* Parses a passed in message stanza and returns an object /* Parses a passed in message stanza and returns an object
* of attributes. * of attributes.
...@@ -666,8 +661,7 @@ converse.plugins.add('converse-chatboxes', { ...@@ -666,8 +661,7 @@ converse.plugins.add('converse-chatboxes', {
* that contains the message stanza, if it was * that contains the message stanza, if it was
* contained, otherwise it's the message stanza itself. * contained, otherwise it's the message stanza itself.
*/ */
const archive = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, original_stanza).pop(), const spoiler = sizzle(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`, original_stanza).pop(),
spoiler = sizzle(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`, original_stanza).pop(),
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop(), delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop(),
text = _converse.chatboxes.getMessageBody(stanza) || undefined, text = _converse.chatboxes.getMessageBody(stanza) || undefined,
chat_state = stanza.getElementsByTagName(_converse.COMPOSING).length && _converse.COMPOSING || chat_state = stanza.getElementsByTagName(_converse.COMPOSING).length && _converse.COMPOSING ||
...@@ -678,7 +672,7 @@ converse.plugins.add('converse-chatboxes', { ...@@ -678,7 +672,7 @@ converse.plugins.add('converse-chatboxes', {
const attrs = _.extend({ const attrs = _.extend({
'chat_state': chat_state, 'chat_state': chat_state,
'is_archived': !_.isNil(archive), 'is_archived': this.isArchived(original_stanza),
'is_delayed': !_.isNil(delay), 'is_delayed': !_.isNil(delay),
'is_spoiler': !_.isNil(spoiler), 'is_spoiler': !_.isNil(spoiler),
'is_single_emoji': text ? u.isSingleEmoji(text) : false, 'is_single_emoji': text ? u.isSingleEmoji(text) : false,
...@@ -926,18 +920,21 @@ converse.plugins.add('converse-chatboxes', { ...@@ -926,18 +920,21 @@ converse.plugins.add('converse-chatboxes', {
roster_nick = _.get(_converse.api.contacts.get(contact_jid), 'attributes.nickname'), roster_nick = _.get(_converse.api.contacts.get(contact_jid), 'attributes.nickname'),
chatbox = this.getChatBox(contact_jid, {'nickname': roster_nick}, has_body); chatbox = this.getChatBox(contact_jid, {'nickname': roster_nick}, has_body);
if (chatbox && if (chatbox) {
!chatbox.findDuplicateFromOriginID(stanza) && const message = await chatbox.getDuplicateMessage(stanza);
!await chatbox.hasDuplicateArchiveID(original_stanza) && if (message) {
!await chatbox.hasDuplicateStanzaID(stanza) && chatbox.updateMessage(message, original_stanza);
!chatbox.handleMessageCorrection(stanza) && }
!chatbox.handleReceipt (stanza, from_jid, is_carbon, is_me) && if (!message &&
!chatbox.handleChatMarker(stanza, from_jid, is_carbon, is_roster_contact)) { !chatbox.handleMessageCorrection(stanza) &&
!chatbox.handleReceipt (stanza, from_jid, is_carbon, is_me) &&
const attrs = await chatbox.getMessageAttributesFromStanza(stanza, original_stanza); !chatbox.handleChatMarker(stanza, from_jid, is_carbon, is_roster_contact)) {
if (attrs['chat_state'] || !u.isEmptyMessage(attrs)) {
const msg = chatbox.messages.create(attrs); const attrs = await chatbox.getMessageAttributesFromStanza(stanza, original_stanza);
chatbox.incrementUnreadMsgCounter(msg); if (attrs['chat_state'] || !u.isEmptyMessage(attrs)) {
const msg = chatbox.messages.create(attrs);
chatbox.incrementUnreadMsgCounter(msg);
}
} }
} }
_converse.emit('message', {'stanza': original_stanza, 'chatbox': chatbox}); _converse.emit('message', {'stanza': original_stanza, 'chatbox': chatbox});
......
...@@ -23,17 +23,6 @@ const RSM_ATTRIBUTES = ['max', 'first', 'last', 'after', 'before', 'index', 'cou ...@@ -23,17 +23,6 @@ const RSM_ATTRIBUTES = ['max', 'first', 'last', 'after', 'before', 'index', 'cou
const MAM_ATTRIBUTES = ['with', 'start', 'end']; const MAM_ATTRIBUTES = ['with', 'start', 'end'];
function getMessageArchiveID (stanza) {
// See https://xmpp.org/extensions/xep-0313.html#results
//
// The result messages MUST contain a <result/> element with an 'id'
// attribute that gives the current message's archive UID
const result = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, stanza).pop();
if (!_.isUndefined(result)) {
return result.getAttribute('id');
}
}
function queryForArchivedMessages (_converse, options, callback, errback) { function queryForArchivedMessages (_converse, options, callback, errback) {
/* Internal function, called by the "archive.query" API method. /* Internal function, called by the "archive.query" API method.
*/ */
...@@ -128,10 +117,38 @@ converse.plugins.add('converse-mam', { ...@@ -128,10 +117,38 @@ converse.plugins.add('converse-mam', {
// New functions which don't exist yet can also be added. // New functions which don't exist yet can also be added.
ChatBox: { ChatBox: {
async getMessageAttributesFromStanza (message, original_stanza) { async findDuplicateFromArchiveID (stanza) {
const attrs = await this.__super__.getMessageAttributesFromStanza.apply(this, arguments); const { _converse } = this.__super__;
attrs.archive_id = getMessageArchiveID(original_stanza); const result = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, stanza).pop();
return attrs; if (!result) {
return null;
}
const by_jid = stanza.getAttribute('from') || this.get('jid');
const supported = await _converse.api.disco.supports(Strophe.NS.MAM, by_jid);
if (!supported.length) {
return null;
}
const query = {};
query[`stanza_id ${by_jid}`] = result.getAttribute('id');
return this.messages.findWhere(query);
},
async getDuplicateMessage (stanza) {
const message = await this.__super__.getDuplicateMessage.apply(this, arguments);
if (!message) {
return this.findDuplicateFromArchiveID(stanza);
}
return message;
},
updateMessage (message, stanza) {
this.__super__.updateMessage.apply(this, arguments);
if (message && !message.get('is_archived')) {
message.save(_.extend({
'is_archived': this.isArchived(stanza)
}, this.getStanzaIDs(stanza)));
}
} }
}, },
...@@ -155,15 +172,11 @@ converse.plugins.add('converse-mam', { ...@@ -155,15 +172,11 @@ converse.plugins.add('converse-mam', {
if (_.isNil(most_recent_msg)) { if (_.isNil(most_recent_msg)) {
this.fetchArchivedMessages(); this.fetchArchivedMessages();
} else { } else {
const archive_id = most_recent_msg.get('archive_id'); const stanza_id = most_recent_msg.get(`stanza_id ${this.model.get('jid')}`);
if (archive_id) { if (stanza_id) {
this.fetchArchivedMessages({ this.fetchArchivedMessages({'after': stanza_id});
'after': most_recent_msg.get('archive_id')
});
} else { } else {
this.fetchArchivedMessages({ this.fetchArchivedMessages({'start': most_recent_msg.get('time')});
'start': most_recent_msg.get('time')
});
} }
} }
}, },
...@@ -250,11 +263,10 @@ converse.plugins.add('converse-mam', { ...@@ -250,11 +263,10 @@ converse.plugins.add('converse-mam', {
const { _converse } = this.__super__; const { _converse } = this.__super__;
if (this.content.scrollTop === 0 && this.model.messages.length) { if (this.content.scrollTop === 0 && this.model.messages.length) {
const oldest_message = this.model.messages.at(0); const oldest_message = this.model.messages.at(0);
const archive_id = oldest_message.get('archive_id'); const by_jid = this.model.get('jid');
if (archive_id) { const stanza_id = oldest_message.get(`stanza_id ${by_jid}`);
this.fetchArchivedMessages({ if (stanza_id) {
'before': archive_id this.fetchArchivedMessages({'before': stanza_id});
});
} else { } else {
this.fetchArchivedMessages({ this.fetchArchivedMessages({
'end': oldest_message.get('time') 'end': oldest_message.get('time')
...@@ -264,20 +276,6 @@ converse.plugins.add('converse-mam', { ...@@ -264,20 +276,6 @@ converse.plugins.add('converse-mam', {
}, },
}, },
ChatRoom: {
isDuplicate (message, original_stanza) {
const result = this.__super__.isDuplicate.apply(this, arguments);
if (result) {
return result;
}
const archive_id = getMessageArchiveID(original_stanza);
if (archive_id) {
return this.messages.filter({'archive_id': archive_id}).length > 0;
}
}
},
ChatRoomView: { ChatRoomView: {
initialize () { initialize () {
......
...@@ -972,33 +972,6 @@ converse.plugins.add('converse-muc', { ...@@ -972,33 +972,6 @@ converse.plugins.add('converse-muc', {
acknowledged[xmlns="${Strophe.NS.MARKERS}"]`, stanza).length > 0; acknowledged[xmlns="${Strophe.NS.MARKERS}"]`, stanza).length > 0;
}, },
handleReflection (stanza) {
/* Handle a MUC reflected message and return true if so.
*
* Parameters:
* (XMLElement) stanza: The message stanza
*/
const from = stanza.getAttribute('from');
const own_message = Strophe.getResourceFromJid(from) == this.get('nick');
if (own_message) {
const msg = this.findDuplicateFromOriginID(stanza);
if (msg) {
const attrs = {};
const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
const by_jid = stanza_id ? stanza_id.getAttribute('by') : undefined;
if (by_jid) {
const key = `stanza_id ${by_jid}`;
attrs[key] = stanza_id.getAttribute('id');
}
if (!msg.get('received')) {
attrs.received = moment().format();
}
msg.save(attrs);
}
return msg ? true : false;
}
},
subjectChangeHandled (attrs) { subjectChangeHandled (attrs) {
/* Handle a subject change and return `true` if so. /* Handle a subject change and return `true` if so.
* *
...@@ -1029,6 +1002,28 @@ converse.plugins.add('converse-muc', { ...@@ -1029,6 +1002,28 @@ converse.plugins.add('converse-muc', {
return is_csn && (attrs.is_delayed || own_message); return is_csn && (attrs.is_delayed || own_message);
}, },
updateMessage (message, stanza) {
/* Make sure that the already cached message is updated with
* the stanza ID.
*/
_converse.ChatBox.prototype.updateMessage.call(this, message, stanza);
const from = stanza.getAttribute('from');
const own_message = Strophe.getResourceFromJid(from) == this.get('nick');
if (own_message) {
const attrs = {};
const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
const by_jid = stanza_id ? stanza_id.getAttribute('by') : undefined;
if (by_jid) {
const key = `stanza_id ${by_jid}`;
attrs[key] = stanza_id.getAttribute('id');
}
if (!message.get('received')) {
attrs.received = moment().format();
}
message.save(attrs);
}
},
async onMessage (stanza) { async onMessage (stanza) {
/* Handler for all MUC messages sent to this groupchat. /* Handler for all MUC messages sent to this groupchat.
* *
...@@ -1042,9 +1037,11 @@ converse.plugins.add('converse-muc', { ...@@ -1042,9 +1037,11 @@ converse.plugins.add('converse-muc', {
if (forwarded) { if (forwarded) {
stanza = forwarded.querySelector('message'); stanza = forwarded.querySelector('message');
} }
if (this.handleReflection(stanza) || const message = await this.getDuplicateMessage(original_stanza);
await this.hasDuplicateArchiveID(original_stanza) || if (message) {
await this.hasDuplicateStanzaID(stanza) || this.updateMessage(message, original_stanza);
}
if (message ||
this.handleMessageCorrection(stanza) || this.handleMessageCorrection(stanza) ||
this.isReceipt(stanza) || this.isReceipt(stanza) ||
this.isChatMarker(stanza)) { this.isChatMarker(stanza)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment