plugins/mod_groups.lua
author Matthew Wild <mwild1@gmail.com>
Mon, 20 Feb 2023 18:10:15 +0000
branch0.12
changeset 12898 0598d822614f
parent 10115 0f335815244f
child 12981 74b9e05af71e
permissions -rw-r--r--
mod_websocket: Fire pre-session-close event (fixes #1800) This event was added in a7c183bb4e64 and is required to make mod_smacks know that a session was intentionally closed and shouldn't be hibernated (see fcea4d9e7502). Because this was missing from mod_websocket's session.close(), mod_smacks would always attempt to hibernate websocket sessions even if they closed cleanly. That mod_websocket has its own copy of session.close() is something to fix another day (probably not in the stable branch). So for now this commit makes the minimal change to get things working again. Thanks to Damian and the Jitsi team for reporting.

-- Prosody IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--


local groups;
local members;

local datamanager = require "util.datamanager";
local jid_prep = require "util.jid".prep;

local module_host = module:get_host();

function inject_roster_contacts(event)
	local username, host= event.username, event.host;
	--module:log("debug", "Injecting group members to roster");
	local bare_jid = username.."@"..host;
	if not members[bare_jid] and not members[false] then return; end -- Not a member of any groups

	local roster = event.roster;
	local function import_jids_to_roster(group_name)
		for jid in pairs(groups[group_name]) do
			-- Add them to roster
			--module:log("debug", "processing jid %s in group %s", jid, group_name);
			if jid ~= bare_jid then
				if not roster[jid] then roster[jid] = {}; end
				roster[jid].subscription = "both";
				if groups[group_name][jid] then
					roster[jid].name = groups[group_name][jid];
				end
				if not roster[jid].groups then
					roster[jid].groups = { [group_name] = true };
				end
				roster[jid].groups[group_name] = true;
				roster[jid].persist = false;
			end
		end
	end

	-- Find groups this JID is a member of
	if members[bare_jid] then
		for _, group_name in ipairs(members[bare_jid]) do
			--module:log("debug", "Importing group %s", group_name);
			import_jids_to_roster(group_name);
		end
	end

	-- Import public groups
	if members[false] then
		for _, group_name in ipairs(members[false]) do
			--module:log("debug", "Importing group %s", group_name);
			import_jids_to_roster(group_name);
		end
	end

	if roster[false] then
		roster[false].version = true;
	end
end

function remove_virtual_contacts(username, host, datastore, data)
	if host == module_host and datastore == "roster" then
		local new_roster = {};
		for jid, contact in pairs(data) do
			if contact.persist ~= false then
				new_roster[jid] = contact;
			end
		end
		if new_roster[false] then
			new_roster[false].version = nil; -- Version is void
		end
		return username, host, datastore, new_roster;
	end

	return username, host, datastore, data;
end

function module.load()
	local groups_file = module:get_option_path("groups_file", nil, "config");
	if not groups_file then return; end

	module:hook("roster-load", inject_roster_contacts);
	datamanager.add_callback(remove_virtual_contacts);

	groups = { default = {} };
	members = { };
	local curr_group = "default";
	for line in io.lines(groups_file) do
		if line:match("^%s*%[.-%]%s*$") then
			curr_group = line:match("^%s*%[(.-)%]%s*$");
			if curr_group:match("^%+") then
				curr_group = curr_group:gsub("^%+", "");
				if not members[false] then
					members[false] = {};
				end
				members[false][#members[false]+1] = curr_group; -- Is a public group
			end
			module:log("debug", "New group: %s", curr_group);
			groups[curr_group] = groups[curr_group] or {};
		else
			-- Add JID
			local entryjid, name = line:match("([^=]*)=?(.*)");
			module:log("debug", "entryjid = '%s', name = '%s'", entryjid, name);
			local jid;
			jid = jid_prep(entryjid:match("%S+"));
			if jid then
				module:log("debug", "New member of %s: %s", curr_group, jid);
				groups[curr_group][jid] = name or false;
				members[jid] = members[jid] or {};
				members[jid][#members[jid]+1] = curr_group;
			elseif entryjid:match("%S") then
				module:log("warn", "Invalid JID: %q", entryjid);
			end
		end
	end
	module:log("info", "Groups loaded successfully");
end

function module.unload()
	datamanager.remove_callback(remove_virtual_contacts);
end

-- Public for other modules to access
function group_contains(group_name, jid)
	return groups[group_name][jid];
end