branch: elpa/jabber
commit bf0656ad99e7c9c47d76d2caab9b25b159473e84
Author: Thanos Apollo <[email protected]>
Commit: Thanos Apollo <[email protected]>
chat: Emit origin-id on outgoing messages
---
CHANGELOG.org | 1 +
doap.xml | 2 +-
lisp/jabber-chat.el | 16 ++++++++++++++--
tests/jabber-test-chat.el | 26 ++++++++++++++++++++++++++
4 files changed, 42 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.org b/CHANGELOG.org
index c355539017..fe7ac2a014 100644
--- a/CHANGELOG.org
+++ b/CHANGELOG.org
@@ -3,6 +3,7 @@
* [Unreleased]
** Added
+- Outgoing messages carry an XEP-0359 origin-id, so replies from other clients
reference a stable id
- OMEMO signed pre-keys now rotate automatically on connect
(~jabber-omemo-signed-pre-key-rotation-period~, 7 days default)
** Fixes
diff --git a/doap.xml b/doap.xml
index 82578c638f..6658127d18 100644
--- a/doap.xml
+++ b/doap.xml
@@ -444,7 +444,7 @@
<xmpp:status>partial</xmpp:status>
<xmpp:version>0.7.0</xmpp:version>
<xmpp:since>0.10.0</xmpp:since>
- <xmpp:note>Origin-id generation on send, stanza-id parsing for MAM
deduplication.</xmpp:note>
+ <xmpp:note>Origin-id stamped on all outgoing messages; stanza-id
parsing for MAM deduplication and reply targets. No disco feature announcement
or referenced-stanza support.</xmpp:note>
</xmpp:SupportedXep>
</implements>
<implements>
diff --git a/lisp/jabber-chat.el b/lisp/jabber-chat.el
index 87e62708f8..b38645a9f9 100644
--- a/lisp/jabber-chat.el
+++ b/lisp/jabber-chat.el
@@ -1033,6 +1033,18 @@ mean the entire element; Dino emits bare <body/> for
full quotes)."
'all))
'all)))
+(defconst jabber-chat--sid-xmlns "urn:xmpp:sid:0"
+ "XEP-0359 unique and stable stanza IDs namespace.")
+
+(defun jabber-chat--origin-id-send-hook (_body id)
+ "Return an XEP-0359 <origin-id/> element carrying ID.
+Stamps every outgoing message so peers replying to us can
+reference a stable id instead of the message id attribute."
+ (and id (list `(origin-id ((xmlns . ,jabber-chat--sid-xmlns)
+ (id . ,id))))))
+
+(add-hook 'jabber-chat-send-hooks #'jabber-chat--origin-id-send-hook)
+
(defun jabber-chat--stanza-id-element (xml-data &optional expected-by)
"Return the first valid XEP-0359 <stanza-id/> child in XML-DATA.
When EXPECTED-BY is non-nil, accept only elements whose `by'
@@ -1041,7 +1053,7 @@ arbitrary `by' values, so groupchat callers must pass the
room JID."
(seq-find
(lambda (child)
(and (eq (jabber-xml-node-name child) 'stanza-id)
- (string= (jabber-xml-get-xmlns child) "urn:xmpp:sid:0")
+ (string= (jabber-xml-get-xmlns child) jabber-chat--sid-xmlns)
(jabber-xml-get-attribute child 'id)
(let ((by (jabber-xml-get-attribute child 'by)))
(and by
@@ -1055,7 +1067,7 @@ Shares its namespace with <stanza-id/>, so match on the
node name."
(let ((el (seq-find
(lambda (child)
(and (eq (jabber-xml-node-name child) 'origin-id)
- (string= (jabber-xml-get-xmlns child) "urn:xmpp:sid:0")))
+ (string= (jabber-xml-get-xmlns child)
jabber-chat--sid-xmlns)))
(jabber-xml-node-children xml-data))))
(and el (jabber-xml-get-attribute el 'id))))
diff --git a/tests/jabber-test-chat.el b/tests/jabber-test-chat.el
index c3423c0e0c..df2794bf5f 100644
--- a/tests/jabber-test-chat.el
+++ b/tests/jabber-test-chat.el
@@ -261,6 +261,32 @@
(plist (jabber-chat--msg-plist-from-stanza stanza)))
(should-not (plist-get plist :fallback-range))))
+(ert-deftest jabber-test-chat-send-hooks-stamp-origin-id ()
+ "The default send hooks stamp an XEP-0359 origin-id on outgoing stanzas."
+ (with-temp-buffer
+ (let ((stanza '(message ((to . "[email protected]")
+ (type . "chat")
+ (id . "m-1"))
+ (body () "hi"))))
+ (jabber-chat--run-send-hooks stanza "hi" "m-1")
+ (let ((el (seq-find (lambda (child)
+ (and (consp child) (eq (car child) 'origin-id)))
+ (jabber-xml-node-children stanza))))
+ (should el)
+ (should (equal "m-1" (jabber-xml-get-attribute el 'id)))
+ (should (equal "urn:xmpp:sid:0" (jabber-xml-get-xmlns el)))))))
+
+(ert-deftest jabber-test-chat-origin-id-round-trip ()
+ "A stanza stamped by the send hook parses back into :origin-id."
+ (with-temp-buffer
+ (let ((stanza '(message ((to . "[email protected]")
+ (type . "chat")
+ (id . "m-2"))
+ (body () "hi"))))
+ (jabber-chat--run-send-hooks stanza "hi" "m-2")
+ (should (equal "m-2" (plist-get (jabber-chat--msg-plist-from-stanza
stanza)
+ :origin-id))))))
+
(ert-deftest jabber-test-chat-plist-reply-fallback-not-masked ()
"A non-reply <fallback> before the reply one must not mask it."
(let* ((stanza '(message ((from . "[email protected]/phone")