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 #
......@@ -1278,8 +1278,8 @@ class DirectChat extends Chat {
12781278 message.from = client.jid;
12791279 message.sender = message.from.asBare();
12801280 message.replyTo = [message.sender];
1281- message.recipients = counterparts().map((p) -> JID.parse(p));
1282- message.to = message.recipients[0];
1281+ message.recipients = _fullCounterparts.map((p) -> JID.parse(p));
1282+ message.to = JID.parse(counterparts()[0]);
12831283 if (message.localId == null) message.localId = ID.unique();
12841284 return message;
12851285 }
......@@ -1309,11 +1309,10 @@ class DirectChat extends Chat {
13091309 if (typingTimer != null) typingTimer.stop();
13101310 client.chatActivity(this);
13111311 message = prepareOutgoingMessage(message);
1312- message.to = message.recipients[0]; // Just pick one for the stanza we re-parse
1312+ final outboxItem = outbox.newItem();
13131313 final fromStanza = Message.fromStanza(message.build().asStanza(), client.jid).parsed;
13141314 switch (fromStanza) {
13151315 case ChatMessageStanza(_):
1316- final outboxItem = outbox.newItem();
13171316 client.storeMessageBuilder(message).then((stored) -> {
13181317 final stanza = message.build().asStanza();
13191318 if (isActive != null) {
......@@ -1334,10 +1333,7 @@ class DirectChat extends Chat {
13341333 });
13351334 case ReactionUpdateStanza(update):
13361335 persistence.storeReaction(client.accountId(), update).then((stored) -> {
1337- for (recipient in message.recipients) {
1338- message.to = recipient;
1339- client.sendStanza(message.build().asStanza());
1340- }
1336+ sendMessageStanza(message.build().asStanza(), outboxItem, e2eePreference);
13411337 if (stored != null) client.notifyMessageHandlers(stored, ReactionEvent);
13421338 });
13431339 default:
+33 -0 test/TestChat.hx #
......@@ -1231,6 +1231,39 @@ class TestChat extends utest.Test {
12311231 }
12321232 #end
12331233
1234+ public function testSendMessageMultiDMSendsOnlyToRoutingJid(async: Async) {
1235+ final persistence = new RecordingPersistence();
1236+ final client = new Client("me@example.com", persistence);
1237+ final routing = "multi@example.com";
1238+ final chat = new borogove.Chat.DirectChat(client, client.stream, persistence, routing);
1239+ chat._fullCounterparts = ["bob@example.com", "carol@example.com"];
1240+
1241+ client.stream.on("sendStanza", (stanza: Stanza) -> {
1242+ if (stanza.name != "message" || stanza.getChildText("body") != "hello") return EventUnhandled;
1243+
1244+ Assert.equals(1, persistence.storedMessages.length);
1245+ if (persistence.storedMessages.length > 0) {
1246+ final stored = persistence.storedMessages[0];
1247+ Assert.equals(routing, stored.chatId());
1248+ Assert.equals(routing, stored.to?.asString());
1249+ Assert.same(["bob@example.com", "carol@example.com"], stored.recipients.map(r -> r.asBare().asString()));
1250+ }
1251+
1252+ Assert.equals(routing, stanza.attr.get("to"));
1253+ final addresses = stanza.getChild("addresses", "http://jabber.org/protocol/address");
1254+ Assert.notNull(addresses);
1255+ if (addresses != null) {
1256+ Assert.same(["bob@example.com", "carol@example.com"], addresses.allTags("address").map(a -> a.attr.get("jid")));
1257+ }
1258+ async.done();
1259+ return EventHandled;
1260+ });
1261+
1262+ final builder = new ChatMessageBuilder();
1263+ builder.text = "hello";
1264+ chat.sendMessage(builder, borogove.Chat.OutgoingE2EEPreference.NoE2EE);
1265+ }
1266+
12341267 public function testSendMessageExtendedMultiDMSendsToEachParticipant(async: Async) {
12351268 final persistence = new RecordingPersistence();
12361269 final client = new Client("me@example.com", persistence);
Back to top