borogove

created pr with borogove/multi-dm.1 on 2026-11-09T19:47:55Z · by 9e834e0d
added borogove/multi-dm.2 on 2026-11-10T19:08:22Z · by 9e834e0d
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 -3
checkout specific patchset revision:
ssh pr.pico.sh pull borogove:multi-dm [rev] | git am -3
add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh borogove:multi-dm
add comment to patch request:
ssh pr.pico.sh comment borogove:multi-dm "lgtm!"
+4 -8 borogove/Chat.hx #
......@@ -1276,8 +1276,8 @@ class DirectChat extends Chat {
12761276 message.from = client.jid;
12771277 message.sender = message.from.asBare();
12781278 message.replyTo = [message.sender];
1279- message.recipients = counterparts().map((p) -> JID.parse(p));
1280- message.to = message.recipients[0];
1279+ message.recipients = _fullCounterparts.map((p) -> JID.parse(p));
1280+ message.to = JID.parse(counterparts()[0]);
12811281 if (message.localId == null) message.localId = ID.unique();
12821282 return message;
12831283 }
......@@ -1307,11 +1307,10 @@ class DirectChat extends Chat {
13071307 if (typingTimer != null) typingTimer.stop();
13081308 client.chatActivity(this);
13091309 message = prepareOutgoingMessage(message);
1310- message.to = message.recipients[0]; // Just pick one for the stanza we re-parse
1310+ final outboxItem = outbox.newItem();
13111311 final fromStanza = Message.fromStanza(message.build().asStanza(), client.jid).parsed;
13121312 switch (fromStanza) {
13131313 case ChatMessageStanza(_):
1314- final outboxItem = outbox.newItem();
13151314 client.storeMessageBuilder(message).then((stored) -> {
13161315 final stanza = message.build().asStanza();
13171316 if (isActive != null) {
......@@ -1327,10 +1326,7 @@ class DirectChat extends Chat {
13271326 });
13281327 case ReactionUpdateStanza(update):
13291328 persistence.storeReaction(client.accountId(), update).then((stored) -> {
1330- for (recipient in message.recipients) {
1331- message.to = recipient;
1332- client.sendStanza(message.build().asStanza());
1333- }
1329+ sendMessageStanza(message.build().asStanza(), outboxItem, e2eePreference);
13341330 if (stored != null) client.notifyMessageHandlers(stored, ReactionEvent);
13351331 });
13361332 default:
+33 -0 test/TestChat.hx #
......@@ -1167,6 +1167,39 @@ class TestChat extends utest.Test {
11671167 }
11681168 #end
11691169
1170+ public function testSendMessageMultiDMSendsOnlyToRoutingJid(async: Async) {
1171+ final persistence = new RecordingPersistence();
1172+ final client = new Client("me@example.com", persistence);
1173+ final routing = "multi@example.com";
1174+ final chat = new borogove.Chat.DirectChat(client, client.stream, persistence, routing);
1175+ chat._fullCounterparts = ["bob@example.com", "carol@example.com"];
1176+
1177+ client.stream.on("sendStanza", (stanza: Stanza) -> {
1178+ if (stanza.name != "message" || stanza.getChildText("body") != "hello") return EventUnhandled;
1179+
1180+ Assert.equals(1, persistence.storedMessages.length);
1181+ if (persistence.storedMessages.length > 0) {
1182+ final stored = persistence.storedMessages[0];
1183+ Assert.equals(routing, stored.chatId());
1184+ Assert.equals(routing, stored.to?.asString());
1185+ Assert.same(["bob@example.com", "carol@example.com"], stored.recipients.map(r -> r.asBare().asString()));
1186+ }
1187+
1188+ Assert.equals(routing, stanza.attr.get("to"));
1189+ final addresses = stanza.getChild("addresses", "http://jabber.org/protocol/address");
1190+ Assert.notNull(addresses);
1191+ if (addresses != null) {
1192+ Assert.same(["bob@example.com", "carol@example.com"], addresses.allTags("address").map(a -> a.attr.get("jid")));
1193+ }
1194+ async.done();
1195+ return EventHandled;
1196+ });
1197+
1198+ final builder = new ChatMessageBuilder();
1199+ builder.text = "hello";
1200+ chat.sendMessage(builder, borogove.Chat.OutgoingE2EEPreference.NoE2EE);
1201+ }
1202+
11701203 public function testSendMessageExtendedMultiDMSendsToEachParticipant(async: Async) {
11711204 final persistence = new RecordingPersistence();
11721205 final client = new Client("me@example.com", persistence);
Back to top