# HG changeset patch # User Jonas Schäfer # Date 1612371792 -3600 # Node ID b3e0295e14a3d26c3387953bdcc8e16db6e21786 # Parent 679be18e6a5e09636c70c22c938992e83af380c9 mod_groups_muc_bookmarks: manage PEP (XEP-0048) bookmarks of group members diff -r 679be18e6a5e -r b3e0295e14a3 mod_groups_muc_bookmarks/mod_groups_muc_bookmarks.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_groups_muc_bookmarks/mod_groups_muc_bookmarks.lua Wed Feb 03 18:03:12 2021 +0100 @@ -0,0 +1,132 @@ +local jid_split = require "util.jid".split; + +local st = require "util.stanza"; + +local mod_groups = module:depends("groups_internal") +local mod_pep = module:depends("pep") + +local PUBSUB_NODE_XEP0048 = "storage:bookmarks"; +local XMLNS_XEP0048 = "storage:bookmarks"; +local XMLNS_XEP0060 = "http://jabber.org/protocol/pubsub"; + +local default_options = { + ["persist_items"] = true; + ["access_model"] = "whitelist"; +}; + +local function get_current_bookmarks(jid, service) + local ok, id, item = service:get_last_item(PUBSUB_NODE_XEP0048, jid) + if not ok or id == nil then + if id == "item-not-found" or id == nil then + -- return empty + return st.stanza("storage", { xmlns = XMLNS_XEP0048 }); + end + return nil, result + end + -- first item is the actual storage element + local hit = item:get_child("storage", XMLNS_XEP0048); + if not hit then + return nil, "internal-server-error" + end + return hit +end + +local function update_bookmarks(jid, service, storage) + local item = st.stanza("item", { xmlns = XMLNS_XEP0060, id = "current" }):add_child(storage) + module:log("debug", "updating bookmarks with %q", item) + local ok, err = service:publish( + PUBSUB_NODE_XEP0048, + jid, + "current", + item, + default_options + ) + if not ok then + module:log("error", "failed to update bookmarks: %s", err) + end +end + +local function find_matching_bookmark(storage, room) + for node in storage:childtags("conference") do + if node.attr.jid == room then + return node + end + end + return nil +end + +local function inject_bookmark(jid, room, autojoin, name) + local pep_service = mod_pep.get_pep_service(jid_split(jid)) + + autojoin = autojoin or false and true + local current = get_current_bookmarks(jid, pep_service) + local existing = find_matching_bookmark(current, room) + if existing then + if autojoin ~= nil then + existing.attr.autojoin = autojoin and "true" or "false" + end + if name ~= nil then + -- do not change already configured names + if not existing.attr.name then + existing.attr.name = name + end + end + done = true + module:log("debug", "found existing matching bookmark, updated") + else + module:log("debug", "no existing bookmark found, adding new") + current:tag("conference", { + name = name, + autojoin = autojoin and "true" or "false", + jid = room, + xmlns = XMLNS_XEP0048, + }) + end + + update_bookmarks(jid, pep_service, current) +end + +local function remove_bookmark(jid, room, autojoin, name) + local pep_service = mod_pep.get_pep_service(jid_split(jid)) + + autojoin = autojoin or false and true + local current = get_current_bookmarks(jid, pep_service) + current:maptags(function (node) + if node.attr.xmlns and node.attr.xmlns ~= XMLNS_XEP0048 then + return node + end + if node.name ~= "conference" then + return node + end + if node.attr.jid == room then + -- remove matching bookmark + return nil + end + return node + end) + + update_bookmarks(jid, pep_service, current) +end + +local function handle_user_added(event) + if not event.group_info.muc_jid then + module:log("debug", "ignoring user added event on group %s because it has no MUC", event.id) + return + end + local jid = event.user .. "@" .. event.host + inject_bookmark(jid, event.group_info.muc_jid, true, event.group_info.name) +end + +local function handle_user_removed(event) + if not event.group_info.muc_jid then + module:log("debug", "ignoring user removed event on group %s because it has no MUC", event.id) + return + end + -- Removing the bookmark is fine as the user just lost any privilege to + -- be in the MUC (as group MUCs are members-only). + local jid = event.user .. "@" .. event.host + remove_bookmark(jid, event.group_info.muc_jid, true, event.group_info.name) +end + +module:hook("group-user-added", handle_user_added) +module:hook("group-user-removed", handle_user_removed)