borogove
created pr with
borogove/multi-dm.1
added borogove/multi-dm.2
1: 0ef2769 = 1: 41e89c8 Use to for chatId if not in recipients
2: 90e5a6a = 2: c323e3d clone should clone attributes
3: d86ea28 = 3: a1199ae Actually send to all recipients
4: 1c1061f ! 4: 94bf87d Never add self as counterpart
5: 9c8aa41 = 5: 32b9fad Extended addressing for sent messages specifies all recipients
6: 2da9124 = 6: ce4d9e1 Always add all recipients to outbound message
7: e7db006 = 7: 350343e Use a shared helper for adding extended addressing
8: 4530ece = 8: 40f662a Add startMultiChat to create multiDMs
9: 6810ba9 = 9: 8043c53 Never include ourselves in incoming chat ids
-: ------- > 10: 68e7246 Cannot MAM or bookmark a multiDM
cmds
checkout latest patchset:
ssh pr.pico.sh pull borogove:multi-dm | git am -3checkout specific patchset revision:
ssh pr.pico.sh pull borogove:multi-dm [rev] | git am -3add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh borogove:multi-dmadd comment to patch request:
ssh pr.pico.sh comment borogove:multi-dm "lgtm!"
Patchset
borogove/multi-dm.2
Use to for chatId if not in recipients
Stephen Paul Weber
clone should clone attributes
2026-11-08T19:15:14ZStephen Paul Weber
Actually send to all recipients
2026-11-09T16:18:06ZStephen Paul Weber
Never add self as counterpart
2026-11-09T16:24:50ZStephen Paul Weber
Extended addressing for sent messages specifies all recipients
2026-11-08T19:20:04ZStephen Paul Weber
Always add all recipients to outbound message
2026-11-08T19:20:46ZStephen Paul Weber
Use a shared helper for adding extended addressing
2026-11-08T19:21:50ZStephen Paul Weber
Add startMultiChat to create multiDMs
2026-11-08T19:32:30ZStephen Paul Weber
→ Never include ourselves in incoming chat ids
2026-11-08T21:01:35ZStephen Paul Weber
Cannot MAM or bookmark a multiDM
2026-11-09T19:40:59ZStephen Paul Weber
2026-11-10T17:34:01Z
Never include ourselves in incoming chat ids
Stephen Paul Weber
2026-11-09T19:40:59ZSemantic diff summary
0 added,
0 modified,
0 signature changed,
0 removed
across 0 analyzed files
(2 files skipped: unsupported file type)
+5
-2
borogove/Message.hx
#
| ... | ... | @@ -192,8 +192,11 @@ class Message { | |
| 192 | 192 | trace("No support for addressing to non-jid", address); | |
| 193 | 193 | return new Message(msg.chatId(), msg.senderId, msg.threadId, UnknownMessageStanza(stanza), encryptionInfo); | |
| 194 | 194 | } else if (address.attr.get("type") == "to" || address.attr.get("type") == "cc") { | |
| 195 | - | recipients[JID.parse(jid).asBare().asString()] = true; | |
| 196 | - | if (!anyExtendedReplyTo) replyTo[JID.parse(jid).asString()] = true; // reply all | |
| 195 | + | final addressJid = JID.parse(jid); | |
| 196 | + | recipients[addressJid.asBare().asString()] = true; | |
| 197 | + | if (!anyExtendedReplyTo && !(msg.direction == MessageReceived && addressJid.asBare().equals(localJidBare))) { | |
| 198 | + | replyTo[addressJid.asString()] = true; // reply all | |
| 199 | + | } | |
| 197 | 200 | } else if (address.attr.get("type") == "replyto" || address.attr.get("type") == "replyroom") { | |
| 198 | 201 | if (!anyExtendedReplyTo) { | |
| 199 | 202 | replyTo.clear(); |
+25
-0
test/TestChatMessage.hx
#
| ... | ... | @@ -259,7 +259,9 @@ class TestChatMessage extends utest.Test { | |
| 259 | 259 | final msg = Message.fromStanza(stanza, JID.parse("me@example.com")); | |
| 260 | 260 | switch (msg.parsed) { | |
| 261 | 261 | case ChatMessageStanza(m): | |
| 262 | + | Assert.equals("alice@example.com", m.chatId()); | |
| 262 | 263 | Assert.same(["alice@example.com", "me@example.com"], m.recipients.map(r -> r.asBare().asString())); | |
| 264 | + | Assert.same(["alice@example.com"], m.replyTo.map(r -> r.asBare().asString())); | |
| 263 | 265 | default: | |
| 264 | 266 | Assert.fail("Expected ChatMessageStanza"); | |
| 265 | 267 | } |
| ... | ... | @@ -363,6 +365,29 @@ class TestChatMessage extends utest.Test { | |
| 363 | 365 | } | |
| 364 | 366 | } | |
| 365 | 367 | ||
| 368 | + | public function testExtendedMultiDMChatIdNeverIncludesSelf() { | |
| 369 | + | final builder = new borogove.ChatMessageBuilder(); | |
| 370 | + | builder.localId = "extended-multi-1"; | |
| 371 | + | builder.direction = MessageSent; | |
| 372 | + | builder.from = JID.parse("alice@example.com"); | |
| 373 | + | builder.senderId = "alice@example.com"; | |
| 374 | + | builder.to = JID.parse("bob@example.com"); | |
| 375 | + | builder.recipients = [JID.parse("bob@example.com"), JID.parse("carol@example.com")]; | |
| 376 | + | builder.replyTo = [JID.parse("alice@example.com")]; | |
| 377 | + | builder.setBody(borogove.Html.text("hi")); | |
| 378 | + | ||
| 379 | + | final stanza = builder.build().asStanza(); | |
| 380 | + | Assert.equals("bob@example.com\ncarol@example.com", Message.fromStanza(stanza, JID.parse("alice@example.com")).chatId); | |
| 381 | + | ||
| 382 | + | final toBob = stanza.clone(); | |
| 383 | + | toBob.attr.set("to", "bob@example.com"); | |
| 384 | + | Assert.equals("alice@example.com\ncarol@example.com", Message.fromStanza(toBob, JID.parse("bob@example.com")).chatId); | |
| 385 | + | ||
| 386 | + | final toCarol = stanza.clone(); | |
| 387 | + | toCarol.attr.set("to", "carol@example.com"); | |
| 388 | + | Assert.equals("alice@example.com\nbob@example.com", Message.fromStanza(toCarol, JID.parse("carol@example.com")).chatId); | |
| 389 | + | } | |
| 390 | + | ||
| 366 | 391 | public function testReactionFallbackSkipsNestedQuotes() { | |
| 367 | 392 | // Build a parent message that itself contains a quote and regular text | |
| 368 | 393 | final parentBuilder = new borogove.ChatMessageBuilder(); |