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.1
→ 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
2026-11-09T19:40:59Z
Use to for chatId if not in recipients
Stephen Paul Weber
2026-11-08T19:15:14ZAn outgoing multiDM that goes to a special target (eg 1,2,3@cheogram.com) has a non-recipient to For outgoing messages, prefer the bare to whenever it is not itself one of the recipients. 1:1 and regular multiDM messages keep using the recipient list.
Semantic diff summary
0 added,
0 modified,
0 signature changed,
0 removed
across 0 analyzed files
(3 files skipped: unsupported file type)
+5
-1
borogove/ChatMessage.hx
#
| ... | ... | @@ -502,7 +502,11 @@ class ChatMessage { | |
| 502 | 502 | if (isIncoming()) { | |
| 503 | 503 | return replyTo.map((r) -> r.asBare().asString()).join("\n"); | |
| 504 | 504 | } else { | |
| 505 | - | return recipients.map((r) -> r.asString()).join("\n"); | |
| 505 | + | // If sent to a non-recipient, use that as the chat id | |
| 506 | + | // e.g. a multiDM sent to 1,2,3@cheogram.com | |
| 507 | + | final bareTo = to.asBare(); | |
| 508 | + | if (!recipients.exists((r) -> r.asBare().equals(bareTo))) return bareTo.asString(); | |
| 509 | + | return recipients.map((r) -> r.asBare().asString()).join("\n"); | |
| 506 | 510 | } | |
| 507 | 511 | } | |
| 508 | 512 |
+6
-1
borogove/ChatMessageBuilder.hx
#
| ... | ... | @@ -379,7 +379,12 @@ class ChatMessageBuilder { | |
| 379 | 379 | if (isIncoming()) { | |
| 380 | 380 | return replyTo.map((r) -> r.asBare().asString()).join("\n"); | |
| 381 | 381 | } else { | |
| 382 | - | return recipients.map((r) -> r.asString()).join("\n"); | |
| 382 | + | final toJid = to; | |
| 383 | + | if (toJid != null) { | |
| 384 | + | final bareTo = toJid.asBare(); | |
| 385 | + | if (!recipients.exists((r) -> r.asBare().equals(bareTo))) return bareTo.asString(); | |
| 386 | + | } | |
| 387 | + | return recipients.map((r) -> r.asBare().asString()).join("\n"); | |
| 383 | 388 | } | |
| 384 | 389 | } | |
| 385 | 390 |
+38
-0
test/TestChatMessageBuilder.hx
#
| ... | ... | @@ -125,4 +126,41 @@ class TestChatMessageBuilder extends utest.Test { | |
| 125 | 126 | final stanza = msg.asStanza(); | |
| 126 | 127 | Assert.isNull(stanza.getChild("request", "urn:xmpp:receipts")); | |
| 127 | 128 | } | |
| 129 | + | ||
| 130 | + | public function testChatIdOutgoingUsesToWhenNotInRecipients() { | |
| 131 | + | final builder = new ChatMessageBuilder(); | |
| 132 | + | builder.direction = MessageSent; | |
| 133 | + | builder.from = JID.parse("me@example.com"); | |
| 134 | + | builder.to = JID.parse("multi@example.com"); | |
| 135 | + | builder.recipients = [JID.parse("bob@example.com"), JID.parse("carol@example.com")]; | |
| 136 | + | builder.replyTo = [JID.parse("me@example.com")]; | |
| 137 | + | Assert.equals("multi@example.com", builder.chatId()); | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | public function testChatIdOutgoingUsesBareTo() { | |
| 141 | + | final builder = new ChatMessageBuilder(); | |
| 142 | + | builder.direction = MessageSent; | |
| 143 | + | builder.from = JID.parse("me@example.com"); | |
| 144 | + | builder.to = JID.parse("multi@example.com/device"); | |
| 145 | + | builder.recipients = [JID.parse("bob@example.com"), JID.parse("carol@example.com")]; | |
| 146 | + | Assert.equals("multi@example.com", builder.chatId()); | |
| 147 | + | } | |
| 148 | + | ||
| 149 | + | public function testChatIdOutgoingUsesRecipientsWhenToIsAmongThem() { | |
| 150 | + | final builder = new ChatMessageBuilder(); | |
| 151 | + | builder.direction = MessageSent; | |
| 152 | + | builder.from = JID.parse("me@example.com"); | |
| 153 | + | builder.to = JID.parse("bob@example.com"); | |
| 154 | + | builder.recipients = [JID.parse("bob@example.com"), JID.parse("carol@example.com")]; | |
| 155 | + | Assert.equals("bob@example.com\ncarol@example.com", builder.chatId()); | |
| 156 | + | } | |
| 157 | + | ||
| 158 | + | public function testChatIdOutgoingSingleRecipient() { | |
| 159 | + | final builder = new ChatMessageBuilder(); | |
| 160 | + | builder.direction = MessageSent; | |
| 161 | + | builder.from = JID.parse("me@example.com"); | |
| 162 | + | builder.to = JID.parse("bob@example.com"); | |
| 163 | + | builder.recipients = [JID.parse("bob@example.com")]; | |
| 164 | + | Assert.equals("bob@example.com", builder.chatId()); | |
| 165 | + | } | |
| 128 | 166 | } |