summaryrefslogtreecommitdiff
path: root/src/mod_shared_roster.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_shared_roster.erl')
-rw-r--r--src/mod_shared_roster.erl291
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).