| author | Eric Roberts
<eric@devl.me> 2026-08-17 16:03:44 UTC |
| committer | Stephen Paul Weber
<singpolyma@singpolyma.net> 2026-08-17 16:18:37 UTC |
| parent | fb3172a95b16870fb347b6f22b9d2e6e7b28886d |
| borogove/Client.hx | +32 | -0 |
| test/TestClient.hx | +54 | -0 |
diff --git a/borogove/Client.hx b/borogove/Client.hx index 9262813..089cb40 100644 --- a/borogove/Client.hx +++ b/borogove/Client.hx @@ -755,6 +755,38 @@ class Client extends EventEmitter { } trace("pubsubNode == "+pubsubNode); + if (isOwnAccount && pubsubNode == "urn:xmpp:bookmarks:1" && pubsubEvent.getItems().length > 0) { + final chatsToUpdate = []; + for (item in pubsubEvent.getItems()) { + if (item.attr.get("id") != null) { + final chat = getChat(item.attr.get("id")); + if (chat == null) { + startChatWith( + item.attr.get("id"), + (caps) -> { + if (caps == null) return Open; + + final identity = caps.identities[0]; + final conf = item.getChild("conference", "urn:xmpp:bookmarks:1"); + if (conf.attr.get("name") == null) { + conf.attr.set("name", identity?.name); + } + return (conf.attr.get("autojoin") == "1" || conf.attr.get("autojoin") == "true" || !caps.isChannel(item.attr.get("id"))) ? Open : Closed; + }, + (chat) -> { + chat.updateFromBookmark(item); + } + ); + } else { + chat.updateFromBookmark(item); + chatsToUpdate.push(chat); + } + } + } + persistence.storeChats(accountId(), chatsToUpdate); + this.trigger("chats/update", chatsToUpdate); + } + #if !NO_OMEMO if(pubsubNode == "eu.siacs.conversations.axolotl.devicelist" && omemo != null) { if(isOwnAccount) { diff --git a/test/TestClient.hx b/test/TestClient.hx index e6ddc71..3065ac2 100644 --- a/test/TestClient.hx +++ b/test/TestClient.hx @@ -215,6 +215,60 @@ class TestClient extends utest.Test { Assert.equals("Test Name", client.displayName()); } + public function testUpdateExistingFromBookmark() { + final persistence = new Dummy(); + final client = new Client("test@example.com", persistence); + final chat = new borogove.Chat.Channel( + client, + client.stream, + persistence, + "room@example.com" + ); + client.chats.push(chat); + + final stanza = new Stanza("message", { xmlns: "jabber:client", from: "test@example.com" }) + .tag("event", { xmlns: "http://jabber.org/protocol/pubsub#event" }) + .tag("items", { node: "urn:xmpp:bookmarks:1" }) + .tag("item", { id: "room@example.com" }) + .tag("conference", { xmlns: "urn:xmpp:bookmarks:1" }) + .tag("extensions") + .textTag("group", "mboa", { xmlns: "jabber:iq:roster" }); + + client.stream.onStanza(stanza); + + Assert.equals(1, client.getChat("room@example.com").getTags().length); + Assert.equals("mboa", client.getChat("room@example.com").getTags()[0]); + } + + public function testCreateNewFromBookmark(async: Async) { + final persistence = new Dummy(); + final client = new Client("test@example.com", persistence); + + final stanza = new Stanza("message", { xmlns: "jabber:client", from: "test@example.com" }) + .tag("event", { xmlns: "http://jabber.org/protocol/pubsub#event" }) + .tag("items", { node: "urn:xmpp:bookmarks:1" }) + .tag("item", { id: "room@example.com" }) + .tag("conference", { xmlns: "urn:xmpp:bookmarks:1" }) + .tag("extensions") + .textTag("group", "mboa", { xmlns: "jabber:iq:roster" }); + + client.stream.on("sendStanza", (stanza: Stanza) -> { + if (stanza.name == "iq" && stanza.findChild("{http://jabber.org/protocol/disco#info}query") != null) { + client.stream.onStanza( + new Stanza("iq", { type: "result", to: "room@example.com", id: stanza.attr.get("id"), from: "stranger@example.com", xmlns: "jabber:client" }) + .tag("query", { xmlns: "http://jabber.org/protocol/disco#info" }) + .tag("identity", { category: "conference", type: "text" }) + ); + } + Assert.equals(1, client.getChat("room@example.com").getTags().length); + Assert.equals("mboa", client.getChat("room@example.com").getTags()[0]); + async.done(); + return EventHandled; + }); + + client.stream.onStanza(stanza); + } + public function testSortAfterDirectChat() { final persistence = new Dummy(); final client = new Client("test@example.com", persistence);