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
Actually send to all recipients
Stephen Paul Weber
2026-11-09T16:24:50ZWas making the clone, but not using it
Semantic diff summary
0 added,
0 modified,
0 signature changed,
0 removed
across 0 analyzed files
(2 files skipped: unsupported file type)
+3
-3
borogove/Chat.hx
#
| ... | ... | @@ -1394,16 +1394,16 @@ class DirectChat extends Chat { | |
| 1394 | 1394 | if (e2eePreference == Default) e2eePreference = client.outgoingE2EEPreference[0]; | |
| 1395 | 1395 | #if NO_OMEMO | |
| 1396 | 1396 | if (e2eePreference != NoE2EE) throw "Selected E2EE preference unsupported"; | |
| 1397 | - | return Promise.resolve(stanza); | |
| 1397 | + | return Promise.resolve(clone); | |
| 1398 | 1398 | #else | |
| 1399 | 1399 | switch (e2eePreference) { | |
| 1400 | 1400 | case OMEMO: | |
| 1401 | 1401 | // As written this falls back to NoE2EE if allowed | |
| 1402 | - | return client.omemo.encryptMessage([JID.parse(counterpart)], stanza).then((encryptedStanza) -> { | |
| 1402 | + | return client.omemo.encryptMessage([JID.parse(counterpart)], clone).then((encryptedStanza) -> { | |
| 1403 | 1403 | return Promise.resolve(encryptedStanza); | |
| 1404 | 1404 | }); | |
| 1405 | 1405 | case NoE2EE: | |
| 1406 | - | return Promise.resolve(stanza); | |
| 1406 | + | return Promise.resolve(clone); | |
| 1407 | 1407 | case Default: | |
| 1408 | 1408 | throw "Impossible"; | |
| 1409 | 1409 | } |
+51
-0
test/TestChat.hx
#
| ... | ... | @@ -1166,6 +1166,57 @@ class TestChat extends utest.Test { | |
| 1166 | 1166 | chat.sendMessage(builder, borogove.Chat.OutgoingE2EEPreference.OMEMO); | |
| 1167 | 1167 | } | |
| 1168 | 1168 | #end | |
| 1169 | + | ||
| 1170 | + | public function testSendMessageExtendedMultiDMSendsToEachParticipant(async: Async) { | |
| 1171 | + | final persistence = new RecordingPersistence(); | |
| 1172 | + | final client = new Client("me@example.com", persistence); | |
| 1173 | + | final chat = client.getDirectChat("bob@example.com\ncarol@example.com"); | |
| 1174 | + | final sent: Array<Stanza> = []; | |
| 1175 | + | ||
| 1176 | + | client.stream.on("sendStanza", (stanza: Stanza) -> { | |
| 1177 | + | if (stanza.name != "message" || stanza.getChildText("body") != "hello") return EventUnhandled; | |
| 1178 | + | sent.push(stanza); | |
| 1179 | + | if (sent.length < 2) return EventUnhandled; | |
| 1180 | + | ||
| 1181 | + | final tos = sent.map(s -> s.attr.get("to")); | |
| 1182 | + | tos.sort(Reflect.compare); | |
| 1183 | + | Assert.same(["bob@example.com", "carol@example.com"], tos); | |
| 1184 | + | for (s in sent) { | |
| 1185 | + | final addresses = s.getChild("addresses", "http://jabber.org/protocol/address"); | |
| 1186 | + | Assert.notNull(addresses); | |
| 1187 | + | if (addresses != null) { | |
| 1188 | + | final jids = addresses.allTags("address").map(a -> a.attr.get("jid")); | |
| 1189 | + | jids.sort(Reflect.compare); | |
| 1190 | + | Assert.same(["bob@example.com", "carol@example.com"], jids); | |
| 1191 | + | } | |
| 1192 | + | } | |
| 1193 | + | ||
| 1194 | + | Assert.equals(1, persistence.storedMessages.length); | |
| 1195 | + | if (persistence.storedMessages.length > 0) { | |
| 1196 | + | final stored = persistence.storedMessages[0]; | |
| 1197 | + | Assert.equals(chat.chatId, stored.chatId()); | |
| 1198 | + | Assert.equals("bob@example.com", stored.to?.asString()); | |
| 1199 | + | Assert.same(["bob@example.com", "carol@example.com"], stored.recipients.map(r -> r.asBare().asString())); | |
| 1200 | + | } | |
| 1201 | + | async.done(); | |
| 1202 | + | return EventHandled; | |
| 1203 | + | }); | |
| 1204 | + | ||
| 1205 | + | final builder = new ChatMessageBuilder(); | |
| 1206 | + | builder.text = "hello"; | |
| 1207 | + | chat.sendMessage(builder, borogove.Chat.OutgoingE2EEPreference.NoE2EE); | |
| 1208 | + | } | |
| 1209 | + | ||
| 1210 | + | } | |
| 1211 | + | ||
| 1212 | + | @:access(borogove) | |
| 1213 | + | class RecordingPersistence extends Dummy { | |
| 1214 | + | public var storedMessages: Array<borogove.ChatMessage> = []; | |
| 1215 | + | ||
| 1216 | + | override public function storeMessages(accountId: String, messages: Array<borogove.ChatMessage>) { | |
| 1217 | + | storedMessages = storedMessages.concat(messages); | |
| 1218 | + | return Promise.resolve(messages); | |
| 1219 | + | } | |
| 1169 | 1220 | } | |
| 1170 | 1221 | ||
| 1171 | 1222 | @:access(borogove) |