diff options
Diffstat (limited to 'src/mod_shared_roster.erl')
-rw-r--r-- | src/mod_shared_roster.erl | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl new file mode 100644 index 00000000..3566da24 --- /dev/null +++ b/src/mod_shared_roster.erl @@ -0,0 +1,291 @@ +%%%---------------------------------------------------------------------- +%%% File : mod_shared_roster.erl +%%% Author : Alexey Shchepin <alexey@sevcom.net> +%%% Purpose : Shared roster management +%%% Created : 5 Mar 2005 by Alexey Shchepin <alexey@sevcom.net> +%%% Id : $Id: mod_shared_roster.erl 24 2005-04-14 01:15:31Z alexey $ +%%%---------------------------------------------------------------------- + +-module(mod_shared_roster). +-author('alexey@sevcom.net'). +-vsn('$Revision: 24 $ '). + +-behaviour(gen_mod). + +-export([start/1, stop/0, + get_user_roster/2, + get_subscription_lists/3, + get_jid_info/4, + in_subscription/5, + out_subscription/4, + list_groups/1, + create_group/2, + create_group/3, + delete_group/2, + get_group_opts/2, + set_group_opts/3, + get_group_users/2, + add_user_to_group/3, + remove_user_from_group/3]). + +-include("ejabberd.hrl"). +-include("jlib.hrl"). +-include("mod_roster.hrl"). + +-record(sr_group, {group_host, opts}). +-record(sr_user, {us, group_host}). + +start(_Opts) -> + mnesia:create_table(sr_group, + [{disc_copies, [node()]}, + {attributes, record_info(fields, sr_group)}]), + mnesia:create_table(sr_user, + [{disc_copies, [node()]}, + {type, bag}, + {attributes, record_info(fields, sr_user)}]), + mnesia:add_table_index(sr_user, group_host), + ejabberd_hooks:add(roster_get, + ?MODULE, get_user_roster, 70), + ejabberd_hooks:add(roster_in_subscription, + ?MODULE, in_subscription, 30), + ejabberd_hooks:add(roster_out_subscription, + ?MODULE, out_subscription, 30), + ejabberd_hooks:add(roster_get_subscription_lists, + ?MODULE, get_subscription_lists, 70), + ejabberd_hooks:add(roster_get_jid_info, + ?MODULE, get_jid_info, 70). + %ejabberd_hooks:add(remove_user, + % ?MODULE, remove_user, 50), + +stop() -> + ejabberd_hooks:delete(roster_get, + ?MODULE, get_user_roster, 70), + ejabberd_hooks:delete(roster_in_subscription, + ?MODULE, in_subscription, 30), + ejabberd_hooks:delete(roster_out_subscription, + ?MODULE, out_subscription, 30), + ejabberd_hooks:delete(roster_get_subscription_lists, + ?MODULE, get_subscription_lists, 70), + ejabberd_hooks:delete(roster_get_jid_info, + ?MODULE, get_jid_info, 70). + %ejabberd_hooks:delete(remove_user, + % ?MODULE, remove_user, 50), + + +get_user_roster(Items, US) -> + {U, S} = US, + DisplayedGroups = get_user_displayed_groups(US), + SRUsers = + lists:foldl( + fun(Group, Acc1) -> + lists:foldl( + fun(User, Acc2) -> + dict:append(User, get_group_name(S, Group), Acc2) + end, Acc1, get_group_users(S, Group)) + end, dict:new(), DisplayedGroups), + {NewItems1, SRUsersRest} = + lists:mapfoldl( + fun(Item, SRUsers1) -> + {_, _, {U1, S1, _}} = Item#roster.usj, + US1 = {U1, S1}, + case dict:find(US1, SRUsers1) of + {ok, _GroupNames} -> + {Item#roster{subscription = both, ask = none}, + dict:erase(US1, SRUsers1)}; + error -> + {Item, SRUsers1} + end + end, SRUsers, Items), + SRItems = [#roster{usj = {U, S, {U1, S1, ""}}, + us = US, + jid = {U1, S1, ""}, + name = "", + subscription = both, + ask = none, + groups = GroupNames} || + {{U1, S1}, GroupNames} <- dict:to_list(SRUsersRest)], + SRItems ++ NewItems1. + +get_subscription_lists({F, T}, User, Server) -> + LUser = jlib:nodeprep(User), + LServer = jlib:nameprep(Server), + US = {LUser, LServer}, + DisplayedGroups = get_user_displayed_groups(US), + SRUsers = + lists:usort( + lists:flatmap( + fun(Group) -> + get_group_users(LServer, Group) + end, DisplayedGroups)), + SRJIDs = [{U1, S1, ""} || {U1, S1} <- SRUsers], + {lists:usort(SRJIDs ++ F), lists:usort(SRJIDs ++ T)}. + +get_jid_info({Subscription, Groups}, User, Server, JID) -> + LUser = jlib:nodeprep(User), + LServer = jlib:nameprep(Server), + US = {LUser, LServer}, + {U1, S1, _} = jlib:jid_tolower(JID), + US1 = {U1, S1}, + DisplayedGroups = get_user_displayed_groups(US), + SRUsers = + lists:foldl( + fun(Group, Acc1) -> + lists:foldl( + fun(User1, Acc2) -> + dict:append( + User1, get_group_name(LServer, Group), Acc2) + end, Acc1, get_group_users(LServer, Group)) + end, dict:new(), DisplayedGroups), + case dict:find(US1, SRUsers) of + {ok, GroupNames} -> + NewGroups = if + Groups == [] -> GroupNames; + true -> Groups + end, + {both, NewGroups}; + error -> + {Subscription, Groups} + end. + +in_subscription(Acc, User, Server, JID, Type) -> + process_subscription(in, User, Server, JID, Type, Acc). + +out_subscription(User, Server, JID, Type) -> + process_subscription(out, User, Server, JID, Type, false). + +process_subscription(Direction, User, Server, JID, _Type, Acc) -> + LUser = jlib:nodeprep(User), + LServer = jlib:nameprep(Server), + US = {LUser, LServer}, + {U1, S1, _} = jlib:jid_tolower(jlib:jid_remove_resource(JID)), + US1 = {U1, S1}, + DisplayedGroups = get_user_displayed_groups(US), + SRUsers = + lists:usort( + lists:flatmap( + fun(Group) -> + get_group_users(LServer, Group) + end, DisplayedGroups)), + case lists:member(US1, SRUsers) of + true -> + case Direction of + in -> + {stop, false}; + out -> + stop + end; + false -> + Acc + end. + +list_groups(Host) -> + mnesia:dirty_select( + sr_group, + [{#sr_group{group_host = {'$1', '$2'}, + _ = '_'}, + [{'==', '$2', Host}], + ['$1']}]). + +create_group(Host, Group) -> + create_group(Host, Group, []). + +create_group(Host, Group, Opts) -> + R = #sr_group{group_host = {Group, Host}, opts = Opts}, + F = fun() -> + mnesia:write(R) + end, + mnesia:transaction(F). + +delete_group(Host, Group) -> + F = fun() -> + mnesia:delete({sr_group, {Group, Host}}) + end, + mnesia:transaction(F). + +get_group_opts(Host, Group) -> + case catch mnesia:dirty_read(sr_group, {Group, Host}) of + [#sr_group{opts = Opts}] -> + Opts; + _ -> + error + end. + +set_group_opts(Host, Group, Opts) -> + R = #sr_group{group_host = {Group, Host}, opts = Opts}, + F = fun() -> + mnesia:write(R) + end, + mnesia:transaction(F). + + + +get_user_groups(US) -> + Host = element(2, US), + case catch mnesia:dirty_read(sr_user, US) of + Rs when is_list(Rs) -> + [Group || #sr_user{group_host = {Group, H}} <- Rs, H == Host]; + _ -> + [] + end. + +is_group_enabled(Host, Group) -> + case catch mnesia:dirty_read(sr_group, {Group, Host}) of + [#sr_group{opts = Opts}] -> + not lists:member(disabled, Opts); + _ -> + false + end. + +get_group_opt(Host, Group, Opt, Default) -> + case catch mnesia:dirty_read(sr_group, {Group, Host}) of + [#sr_group{opts = Opts}] -> + case lists:keysearch(Opt, 1, Opts) of + {value, {_, Val}} -> + Val; + false -> + Default + end; + _ -> + false + end. + +get_group_users(Host, Group) -> + case catch mnesia:dirty_index_read( + sr_user, {Group, Host}, #sr_user.group_host) of + Rs when is_list(Rs) -> + [R#sr_user.us || R <- Rs]; + _ -> + [] + end. + +get_group_name(Host, Group) -> + get_group_opt(Host, Group, name, Group). + +get_user_displayed_groups(US) -> + Host = element(2, US), + DisplayedGroups1 = + lists:usort( + lists:flatmap( + fun(Group) -> + case is_group_enabled(Host, Group) of + true -> + get_group_opt(Host, Group, displayed_groups, []); + false -> + [] + end + end, get_user_groups(US))), + [Group || Group <- DisplayedGroups1, is_group_enabled(Host, Group)]. + +add_user_to_group(Host, US, Group) -> + R = #sr_user{us = US, group_host = {Group, Host}}, + F = fun() -> + mnesia:write(R) + end, + mnesia:transaction(F). + +remove_user_from_group(Host, US, Group) -> + R = #sr_user{us = US, group_host = {Group, Host}}, + F = fun() -> + mnesia:delete_object(R) + end, + mnesia:transaction(F). |