Commit e1f8d53c authored by JC Brand's avatar JC Brand

Initial support for chat markers. Updates #324

parent 4c964c56
......@@ -61304,6 +61304,7 @@ const u = _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].env.utils;
Strophe.addNamespace('MESSAGE_CORRECT', 'urn:xmpp:message-correct:0');
Strophe.addNamespace('RECEIPTS', 'urn:xmpp:receipts');
Strophe.addNamespace('REFERENCE', 'urn:xmpp:reference:0');
Strophe.addNamespace('MARKERS', 'urn:xmpp:chat-markers:0');
_converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-chatboxes', {
dependencies: ["converse-roster", "converse-vcard"],
......@@ -61634,7 +61635,84 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
return false;
},
handleReceipt(stanza) {
sendMarker(to_jid, id, type) {
const stanza = $msg({
'from': _converse.connection.jid,
'id': _converse.connection.getUniqueId(),
'to': to_jid,
'type': 'chat'
}).c(type, {
'xmlns': Strophe.NS.MARKERS,
'id': id
});
_converse.api.send(stanza);
},
handleChatMarker(stanza, from_jid, is_carbon) {
const to_bare_jid = Strophe.getBareJidFromJid(stanza.getAttribute('to'));
if (to_bare_jid !== _converse.bare_jid) {
return false;
}
const markers = sizzle(`[xmlns="${Strophe.NS.MARKERS}"]`, stanza);
if (markers.length === 0) {
return false;
} else if (markers.length > 1) {
_converse.log('onMessage: Ignoring incoming stanza with multiple message markers', Strophe.LogLevel.ERROR);
_converse.log(stanza, Strophe.LogLevel.ERROR);
return false;
} else {
const marker = markers.pop();
if (marker.nodeName === 'markable' && !is_carbon) {
this.sendMarker(from_jid, stanza.getAttribute('id'), 'received');
return false;
} else {
const msgid = marker && marker.getAttribute('id'),
message = msgid && this.messages.findWhere({
msgid
}),
field_name = `marker_${marker.nodeName}`;
if (message && !message.get(field_name)) {
message.save({
field_name: moment().format()
});
}
return true;
}
}
},
sendReceiptStanza(to_jid, id) {
const receipt_stanza = $msg({
'from': _converse.connection.jid,
'id': _converse.connection.getUniqueId(),
'to': to_jid,
'type': 'chat'
}).c('received', {
'xmlns': Strophe.NS.RECEIPTS,
'id': id
}).up().c('store', {
'xmlns': Strophe.NS.HINTS
}).up();
_converse.api.send(receipt_stanza);
},
handleReceipt(stanza, from_jid, is_carbon, is_me) {
const requests_receipt = !_.isUndefined(sizzle(`request[xmlns="${Strophe.NS.RECEIPTS}"]`, stanza).pop());
if (requests_receipt && !is_carbon && !is_me) {
this.sendReceiptStanza(from_jid, stanza.getAttribute('id'));
}
const to_bare_jid = Strophe.getBareJidFromJid(stanza.getAttribute('to'));
if (to_bare_jid === _converse.bare_jid) {
......@@ -61927,6 +62005,23 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
return attrs;
},
async createMessage(stanza, original_stanza) {
const msgid = stanza.getAttribute('id'),
message = msgid && this.messages.findWhere({
msgid
});
if (!message) {
// Only create the message when we're sure it's not a duplicate
const attrs = await this.getMessageAttributesFromStanza(stanza, original_stanza);
if (attrs['chat_state'] || !u.isEmptyMessage(attrs)) {
const msg = this.messages.create(attrs);
this.incrementUnreadMsgCounter(msg);
}
}
},
isHidden() {
/* Returns a boolean to indicate whether a newly received
* message will be visible to the user or not.
......@@ -62078,22 +62173,6 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
}
},
sendReceiptStanza(to_jid, id) {
const receipt_stanza = $msg({
'from': _converse.connection.jid,
'id': _converse.connection.getUniqueId(),
'to': to_jid,
'type': 'chat'
}).c('received', {
'xmlns': Strophe.NS.RECEIPTS,
'id': id
}).up().c('store', {
'xmlns': Strophe.NS.HINTS
}).up();
_converse.api.send(receipt_stanza);
},
async onMessage(stanza) {
/* Handler method for all incoming single-user chat "message"
* stanzas.
......@@ -62141,12 +62220,6 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
const from_bare_jid = Strophe.getBareJidFromJid(from_jid),
from_resource = Strophe.getResourceFromJid(from_jid),
is_me = from_bare_jid === _converse.bare_jid;
const requests_receipt = !_.isUndefined(sizzle(`request[xmlns="${Strophe.NS.RECEIPTS}"]`, stanza).pop());
if (requests_receipt && !is_carbon && !is_me) {
this.sendReceiptStanza(from_jid, stanza.getAttribute('id'));
}
let contact_jid;
if (is_me) {
......@@ -62158,27 +62231,17 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
contact_jid = Strophe.getBareJidFromJid(to_jid);
} else {
contact_jid = from_bare_jid;
}
const attrs = {
'fullname': _.get(_converse.api.contacts.get(contact_jid), 'attributes.fullname') // Get chat box, but only create a new one when the message has a body.
} // Get chat box, but only create when the message has something to show to the user
};
const has_body = sizzle(`body, encrypted[xmlns="${Strophe.NS.OMEMO}"]`, stanza).length > 0;
const chatbox = this.getChatBox(contact_jid, attrs, has_body);
if (chatbox && !chatbox.handleMessageCorrection(stanza) && !chatbox.handleReceipt(stanza)) {
const msgid = stanza.getAttribute('id'),
message = msgid && chatbox.messages.findWhere({
msgid
});
const has_body = sizzle(`body, encrypted[xmlns="${Strophe.NS.OMEMO}"]`, stanza).length > 0,
chatbox_attrs = {
'fullname': _.get(_converse.api.contacts.get(contact_jid), 'attributes.fullname')
},
chatbox = this.getChatBox(contact_jid, chatbox_attrs, has_body);
if (!message) {
// Only create the message when we're sure it's not a duplicate
const attrs = await chatbox.getMessageAttributesFromStanza(stanza, original_stanza);
const msg = chatbox.messages.create(attrs);
chatbox.incrementUnreadMsgCounter(msg);
}
if (chatbox && !chatbox.handleMessageCorrection(stanza) && !chatbox.handleReceipt(stanza, from_jid, is_carbon, is_me) && !chatbox.handleChatMarker(stanza, from_jid, is_carbon)) {
await chatbox.createMessage(stanza, original_stanza);
}
_converse.emit('message', {
......@@ -530,6 +530,38 @@
describe("A Chat Status Notification", function () {
it("is ignored when it's a carbon copy of one of my own",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
async function (done, _converse) {
test_utils.createContacts(_converse, 'current');
test_utils.openControlBox();
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
await test_utils.openChatBoxFor(_converse, sender_jid);
let stanza = Strophe.xmlHtmlNode(
`<message from="${sender_jid}"
type="chat"
to="dummy@localhost/resource">
<composing xmlns="http://jabber.org/protocol/chatstates"/>
<no-store xmlns="urn:xmpp:hints"/>
<no-permanent-store xmlns="urn:xmpp:hints"/>
</message>`).firstChild;
_converse.connection._dataRecv(test_utils.createRequest(stanza));
stanza = Strophe.xmlHtmlNode(
`<message from="${sender_jid}"
type="chat"
to="dummy@localhost/resource">
<paused xmlns="http://jabber.org/protocol/chatstates"/>
<no-store xmlns="urn:xmpp:hints"/>
<no-permanent-store xmlns="urn:xmpp:hints"/>
</message>`).firstChild;
_converse.connection._dataRecv(test_utils.createRequest(stanza));
done();
}));
it("does not open a new chatbox",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
......@@ -656,12 +688,14 @@
async function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
// See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions
spyOn(_converse, 'emit');
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, sender_jid);
await test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
await test_utils.openChatBoxFor(_converse, sender_jid);
// <composing> state
let msg = $msg({
......@@ -678,7 +712,6 @@
await test_utils.waitUntil(() => view.model.vcard.get('fullname') === mock.cur_names[1])
// Check that the notification appears inside the chatbox in the DOM
let events = view.el.querySelectorAll('.chat-state-notification');
expect(events.length).toBe(1);
expect(events[0].textContent).toEqual(mock.cur_names[1] + ' is typing');
// Check that it doesn't appear twice
......@@ -687,7 +720,7 @@
to: _converse.connection.jid,
type: 'chat',
id: (new Date()).getTime()
}).c('body').c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
}).c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
await _converse.chatboxes.onMessage(msg);
events = view.el.querySelectorAll('.chat-state-notification');
expect(events.length).toBe(1);
......@@ -802,24 +835,24 @@
null, ['rosterGroupsFetched'], {},
async function (done, _converse) {
test_utils.createContacts(_converse, 'current');
test_utils.createContacts(_converse, 'current', 2);
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
await test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
// TODO: only show paused state if the previous state was composing
// See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions
spyOn(_converse, 'emit');
spyOn(_converse, 'emit').and.callThrough();
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
const view = await test_utils.openChatBoxFor(_converse, sender_jid);
// <paused> state
const msg = $msg({
from: sender_jid,
to: _converse.connection.jid,
type: 'chat',
id: (new Date()).getTime()
}).c('body').c('paused', {'xmlns': Strophe.NS.CHATSTATES}).tree();
}).c('paused', {'xmlns': Strophe.NS.CHATSTATES}).tree();
await _converse.chatboxes.onMessage(msg);
expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
const view = _converse.chatboxviews.get(sender_jid);
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
await test_utils.waitUntil(() => view.model.vcard.get('fullname') === mock.cur_names[1])
var event = view.el.querySelector('.chat-info.chat-state-notification');
expect(event.textContent).toEqual(mock.cur_names[1] + ' has stopped typing');
......
......@@ -313,8 +313,6 @@
await _converse.chatboxes.onMessage(msg);
await test_utils.waitUntil(() => _converse.api.chats.get().length);
const view = _converse.chatboxviews.get(sender_jid);
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
msg = $msg({'id': 'aeb214', 'to': _converse.bare_jid})
.c('forwarded', {'xmlns': 'urn:xmpp:forward:0'})
.c('delay', {'xmlns': 'urn:xmpp:delay', 'stamp':'2017-12-31T22:08:25Z'}).up()
......@@ -392,7 +390,6 @@
.c('composing', {'xmlns': Strophe.NS.CHATSTATES}).up()
.tree();
await _converse.chatboxes.onMessage(msg);
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
msg = $msg({
'id': 'aeb220',
......@@ -527,7 +524,6 @@
await test_utils.waitUntil(() => _converse.api.chats.get().length)
const chatbox = _converse.chatboxes.get(sender_jid);
const view = _converse.chatboxviews.get(sender_jid);
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
expect(chatbox).toBeDefined();
expect(view).toBeDefined();
......@@ -579,7 +575,6 @@
// Check that the chatbox and its view now exist
const chatbox = _converse.chatboxes.get(recipient_jid);
const view = _converse.chatboxviews.get(recipient_jid);
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
expect(chatbox).toBeDefined();
expect(view).toBeDefined();
// Check that the message was received and check the message parameters
......@@ -1225,7 +1220,8 @@
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
const msg_id = u.getUniqueId();
const sent_stanzas = [];
spyOn(_converse.chatboxes, 'sendReceiptStanza').and.callThrough();
const view = await test_utils.openChatBoxFor(_converse, sender_jid);
spyOn(view.model, 'sendReceiptStanza').and.callThrough();
const msg = $msg({
'from': sender_jid,
'to': _converse.connection.jid,
......@@ -1243,7 +1239,7 @@
.c('request', {'xmlns': Strophe.NS.RECEIPTS}).tree();
await _converse.chatboxes.onMessage(msg);
await test_utils.waitUntil(() => _converse.api.chats.get().length);
expect(_converse.chatboxes.sendReceiptStanza).not.toHaveBeenCalled();
expect(view.model.sendReceiptStanza).not.toHaveBeenCalled();
done();
}));
......@@ -1255,7 +1251,8 @@
const recipient_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
const msg_id = u.getUniqueId();
const sent_stanzas = [];
spyOn(_converse.chatboxes, 'sendReceiptStanza').and.callThrough();
const view = await test_utils.openChatBoxFor(_converse, recipient_jid);
spyOn(view.model, 'sendReceiptStanza').and.callThrough();
const msg = $msg({
'from': converse.bare_jid,
'to': _converse.connection.jid,
......@@ -1272,7 +1269,7 @@
.c('request', {'xmlns': Strophe.NS.RECEIPTS}).tree();
await _converse.chatboxes.onMessage(msg);
await test_utils.waitUntil(() => _converse.api.chats.get().length);
expect(_converse.chatboxes.sendReceiptStanza).not.toHaveBeenCalled();
expect(view.model.sendReceiptStanza).not.toHaveBeenCalled();
done();
}));
......@@ -1482,7 +1479,6 @@
// Check that the chatbox and its view now exist
const chatbox = _converse.chatboxes.get(sender_jid);
const view = _converse.chatboxviews.get(sender_jid);
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
expect(chatbox).toBeDefined();
expect(view).toBeDefined();
......@@ -1531,7 +1527,6 @@
await test_utils.waitUntil(() => _converse.api.chats.get().length)
const view = _converse.chatboxviews.get(sender_jid);
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
// onMessage is a handler for received XMPP messages
......@@ -1843,7 +1838,6 @@
await _converse.chatboxes.onMessage(msg);
await test_utils.waitUntil(() => _converse.chatboxviews.keys().length > 1, 1000);
const view = _converse.chatboxviews.get(sender_jid);
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
await test_utils.waitUntil(() => view.model.messages.length);
expect(_converse.chatboxes.getChatBox).toHaveBeenCalled();
var chat_content = $(view.el).find('.chat-content:last')[0];
......@@ -2023,6 +2017,88 @@
});
});
describe("A XEP-0333 Chat Marker", function () {
it("is sent when a markable message is received",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
async function (done, _converse) {
test_utils.createContacts(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
await test_utils.openChatBoxFor(_converse, contact_jid);
const view = await _converse.api.chatviews.get(contact_jid);
const msgid = u.getUniqueId();
const stanza = Strophe.xmlHtmlNode(`
<message from='${contact_jid}'
id='${msgid}'
type="chat"
to='${_converse.jid}'>
<body>My lord, dispatch; read o'er these articles.</body>
<markable xmlns='urn:xmpp:chat-markers:0'/>
</message>`).firstElementChild;
const sent_stanzas = [];
spyOn(_converse.connection, 'send').and.callFake(s => sent_stanzas.push(s));
spyOn(view.model, 'sendMarker').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => view.model.sendMarker.calls.count() === 1);
expect(Strophe.serialize(sent_stanzas[0])).toBe(
`<message from="dummy@localhost/resource" `+
`id="${sent_stanzas[0].nodeTree.getAttribute('id')}" `+
`to="${contact_jid}" type="chat" xmlns="jabber:client">`+
`<received id="${msgid}" xmlns="urn:xmpp:chat-markers:0"/>`+
`</message>`);
done();
}));
it("is ignored if it's a carbon copy of one that I sent from a different client",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
async function (done, _converse) {
test_utils.createContacts(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
await test_utils.openChatBoxFor(_converse, contact_jid);
const view = await _converse.api.chatviews.get(contact_jid);
let stanza = Strophe.xmlHtmlNode(`
<message xmlns="jabber:client"
to="${_converse.bare_jid}"
type="chat"
id="2e972ea0-0050-44b7-a830-f6638a2595b3"
from="${contact_jid}">
<body>😊</body>
<markable xmlns="urn:xmpp:chat-markers:0"/>
<origin-id xmlns="urn:xmpp:sid:0" id="2e972ea0-0050-44b7-a830-f6638a2595b3"/>
<stanza-id xmlns="urn:xmpp:sid:0" id="IxVDLJ0RYbWcWvqC" by="${_converse.bare_jid}"/>
</message>`).firstElementChild;
_converse.connection._dataRecv(test_utils.createRequest(stanza));
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(view.model.messages.length).toBe(1);
stanza = Strophe.xmlHtmlNode(
`<message xmlns="jabber:client" to="${_converse.bare_jid}" type="chat" from="${contact_jid}">
<sent xmlns="urn:xmpp:carbons:2">
<forwarded xmlns="urn:xmpp:forward:0">
<message xmlns="jabber:client" to="${contact_jid}" type="chat" from="${_converse.bare_jid}/other-resource">
<received xmlns="urn:xmpp:chat-markers:0" id="2e972ea0-0050-44b7-a830-f6638a2595b3"/>
<store xmlns="urn:xmpp:hints"/>
<stanza-id xmlns="urn:xmpp:sid:0" id="F4TC6CvHwzqRbeHb" by="jc@opkode.com"/>
</message>
</forwarded>
</sent>
</message>`).firstElementChild;
spyOn(_converse, 'emit').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => _converse.emit.calls.count() === 1);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(view.model.messages.length).toBe(1);
done();
}));
});
describe("A Groupchat Message", function () {
......
......@@ -15,6 +15,7 @@ const u = converse.env.utils;
Strophe.addNamespace('MESSAGE_CORRECT', 'urn:xmpp:message-correct:0');
Strophe.addNamespace('RECEIPTS', 'urn:xmpp:receipts');
Strophe.addNamespace('REFERENCE', 'urn:xmpp:reference:0');
Strophe.addNamespace('MARKERS', 'urn:xmpp:chat-markers:0');
converse.plugins.add('converse-chatboxes', {
......@@ -312,8 +313,66 @@ converse.plugins.add('converse-chatboxes', {
}
return false;
},
sendMarker(to_jid, id, type) {
const stanza = $msg({
'from': _converse.connection.jid,
'id': _converse.connection.getUniqueId(),
'to': to_jid,
'type': 'chat',
}).c(type, {'xmlns': Strophe.NS.MARKERS, 'id': id});
_converse.api.send(stanza);
},
handleReceipt (stanza) {
handleChatMarker (stanza, from_jid, is_carbon) {
const to_bare_jid = Strophe.getBareJidFromJid(stanza.getAttribute('to'));
if (to_bare_jid !== _converse.bare_jid) {
return false;
}
const markers = sizzle(`[xmlns="${Strophe.NS.MARKERS}"]`, stanza);
if (markers.length === 0) {
return false;
} else if (markers.length > 1) {
_converse.log(
'onMessage: Ignoring incoming stanza with multiple message markers',
Strophe.LogLevel.ERROR
);
_converse.log(stanza, Strophe.LogLevel.ERROR);
return false;
} else {
const marker = markers.pop();
if (marker.nodeName === 'markable' && !is_carbon) {
this.sendMarker(from_jid, stanza.getAttribute('id'), 'received');
return false;
} else {
const msgid = marker && marker.getAttribute('id'),
message = msgid && this.messages.findWhere({msgid}),
field_name = `marker_${marker.nodeName}`;
if (message && !message.get(field_name)) {
message.save({field_name: moment().format()});
}
return true;
}
}
},
sendReceiptStanza (to_jid, id) {
const receipt_stanza = $msg({
'from': _converse.connection.jid,
'id': _converse.connection.getUniqueId(),
'to': to_jid,
'type': 'chat',
}).c('received', {'xmlns': Strophe.NS.RECEIPTS, 'id': id}).up()
.c('store', {'xmlns': Strophe.NS.HINTS}).up();
_converse.api.send(receipt_stanza);
},
handleReceipt (stanza, from_jid, is_carbon, is_me) {
const requests_receipt = !_.isUndefined(sizzle(`request[xmlns="${Strophe.NS.RECEIPTS}"]`, stanza).pop());
if (requests_receipt && !is_carbon && !is_me) {
this.sendReceiptStanza(from_jid, stanza.getAttribute('id'));
}
const to_bare_jid = Strophe.getBareJidFromJid(stanza.getAttribute('to'));
if (to_bare_jid === _converse.bare_jid) {
const receipt = sizzle(`received[xmlns="${Strophe.NS.RECEIPTS}"]`, stanza).pop();
......@@ -321,9 +380,7 @@ converse.plugins.add('converse-chatboxes', {
const msgid = receipt && receipt.getAttribute('id'),
message = msgid && this.messages.findWhere({msgid});
if (message && !message.get('received')) {
message.save({
'received': moment().format()
});
message.save({'received': moment().format()});
}
return true;
}
......@@ -575,6 +632,19 @@ converse.plugins.add('converse-chatboxes', {
return attrs;
},
async createMessage (stanza, original_stanza) {
const msgid = stanza.getAttribute('id'),
message = msgid && this.messages.findWhere({msgid});
if (!message) {
// Only create the message when we're sure it's not a duplicate
const attrs = await this.getMessageAttributesFromStanza(stanza, original_stanza);
if (attrs['chat_state'] || !u.isEmptyMessage(attrs)) {
const msg = this.messages.create(attrs);
this.incrementUnreadMsgCounter(msg);
}
}
},
isHidden () {
/* Returns a boolean to indicate whether a newly received
* message will be visible to the user or not.
......@@ -708,17 +778,6 @@ converse.plugins.add('converse-chatboxes', {
}
},
sendReceiptStanza (to_jid, id) {
const receipt_stanza = $msg({
'from': _converse.connection.jid,
'id': _converse.connection.getUniqueId(),
'to': to_jid,
'type': 'chat',
}).c('received', {'xmlns': Strophe.NS.RECEIPTS, 'id': id}).up()
.c('store', {'xmlns': Strophe.NS.HINTS}).up();
_converse.api.send(receipt_stanza);
},
async onMessage (stanza) {
/* Handler method for all incoming single-user chat "message"
* stanzas.
......@@ -765,16 +824,10 @@ converse.plugins.add('converse-chatboxes', {
from_jid = stanza.getAttribute('from');
to_jid = stanza.getAttribute('to');
}
const from_bare_jid = Strophe.getBareJidFromJid(from_jid),
from_resource = Strophe.getResourceFromJid(from_jid),
is_me = from_bare_jid === _converse.bare_jid;
const requests_receipt = !_.isUndefined(sizzle(`request[xmlns="${Strophe.NS.RECEIPTS}"]`, stanza).pop());
if (requests_receipt && !is_carbon && !is_me) {
this.sendReceiptStanza(from_jid, stanza.getAttribute('id'));
}
let contact_jid;
if (is_me) {
// I am the sender, so this must be a forwarded message...
......@@ -788,21 +841,15 @@ converse.plugins.add('converse-chatboxes', {
} else {
contact_jid = from_bare_jid;
}
const attrs = {
'fullname': _.get(_converse.api.contacts.get(contact_jid), 'attributes.fullname')
}
// Get chat box, but only create a new one when the message has a body.
const has_body = sizzle(`body, encrypted[xmlns="${Strophe.NS.OMEMO}"]`, stanza).length > 0;
const chatbox = this.getChatBox(contact_jid, attrs, has_body);
if (chatbox && !chatbox.handleMessageCorrection(stanza) && !chatbox.handleReceipt(stanza)) {
const msgid = stanza.getAttribute('id'),
message = msgid && chatbox.messages.findWhere({msgid});
if (!message) {
// Only create the message when we're sure it's not a duplicate
const attrs = await chatbox.getMessageAttributesFromStanza(stanza, original_stanza);
const msg = chatbox.messages.create(attrs);
chatbox.incrementUnreadMsgCounter(msg);
}
// Get chat box, but only create when the message has something to show to the user
const has_body = sizzle(`body, encrypted[xmlns="${Strophe.NS.OMEMO}"]`, stanza).length > 0,
chatbox_attrs = {'fullname': _.get(_converse.api.contacts.get(contact_jid), 'attributes.fullname')},
chatbox = this.getChatBox(contact_jid, chatbox_attrs, has_body);
if (chatbox &&
!chatbox.handleMessageCorrection(stanza) &&
!chatbox.handleReceipt (stanza, from_jid, is_carbon, is_me) &&
!chatbox.handleChatMarker(stanza, from_jid, is_carbon)) {
await chatbox.createMessage(stanza, original_stanza);
}
_converse.emit('message', {'stanza': original_stanza, 'chatbox': chatbox});
},
......
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