Res
end, {error, not_allowed}, auth_modules(Server)).
+%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, not_allowed}
try_register(_User, _Server, "") ->
%% We do not allow empty password
{error, not_allowed};
false ->
case lists:member(jlib:nameprep(Server), ?MYHOSTS) of
true ->
- lists:foldl(
+ Res = lists:foldl(
fun(_M, {atomic, ok} = Res) ->
Res;
(M, _) ->
M:try_register(User, Server, Password)
- end, {error, not_allowed}, auth_modules(Server));
+ end, {error, not_allowed}, auth_modules(Server)),
+ case Res of
+ {atomic, ok} ->
+ ejabberd_hooks:run(register_user, Server,
+ [User, Server]),
+ {atomic, ok};
+ _ -> Res
+ end;
false ->
{error, not_allowed}
end
M:is_user_exists(User, Server)
end, auth_modules(Server)--[Module]).
+%% @spec (User, Server) -> ok | error | {error, not_allowed}
+%% Remove user.
+%% Note: it may return ok even if there was some problem removing the user.
remove_user(User, Server) ->
- lists:foreach(
+ R = lists:foreach(
fun(M) ->
M:remove_user(User, Server)
- end, auth_modules(Server)).
+ end, auth_modules(Server)),
+ case R of
+ ok -> ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User, Server]);
+ _ -> none
+ end,
+ R.
+%% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request | error
+%% Try to remove user if the provided password is correct.
+%% The removal is attempted in each auth method provided:
+%% when one returns 'ok' the loop stops;
+%% if no method returns 'ok' then it returns the error message indicated by the last method attempted.
remove_user(User, Server, Password) ->
- lists:foreach(
- fun(M) ->
+ R = lists:foldl(
+ fun(_M, ok = Res) ->
+ Res;
+ (M, _) ->
M:remove_user(User, Server, Password)
- end, auth_modules(Server)).
+ end, error, auth_modules(Server)),
+ case R of
+ ok -> ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User, Server]);
+ _ -> none
+ end,
+ R.
%%%----------------------------------------------------------------------
process_item/2,
in_subscription/6,
out_subscription/4,
- user_registered/2,
+ register_user/2,
+ remove_user/2,
list_groups/1,
create_group/2,
create_group/3,
set_group_opts/3,
get_group_users/2,
get_group_explicit_users/2,
+ is_user_in_group/3,
add_user_to_group/3,
remove_user_from_group/3]).
?MODULE, get_jid_info, 70),
ejabberd_hooks:add(roster_process_item, Host,
?MODULE, process_item, 50),
- ejabberd_hooks:add(user_registered, Host,
- ?MODULE, user_registered, 50).
+ ejabberd_hooks:add(register_user, Host,
+ ?MODULE, register_user, 50),
+ ejabberd_hooks:add(remove_user, Host,
+ ?MODULE, remove_user, 50).
%%ejabberd_hooks:add(remove_user, Host,
%% ?MODULE, remove_user, 50),
?MODULE, get_jid_info, 70),
ejabberd_hooks:delete(roster_process_item, Host,
?MODULE, process_item, 50),
- ejabberd_hooks:delete(user_registered, Host,
- ?MODULE, user_registered, 50).
+ ejabberd_hooks:delete(register_user, Host,
+ ?MODULE, register_user, 50),
+ ejabberd_hooks:delete(remove_user, Host,
+ ?MODULE, remove_user, 50).
%%ejabberd_hooks:delete(remove_user, Host,
%% ?MODULE, remove_user, 50),
[]
end ++ get_group_explicit_users(Host, Group).
+%% @spec (Host::string(), Group::string()) -> [{User::string(), Server::string()}]
get_group_explicit_users(Host, Group) ->
Read = (catch mnesia:dirty_index_read(
sr_user,
get_group_name(Host, Group) ->
get_group_opt(Host, Group, name, Group).
+%% Get list of names of groups that have @all@ in the memberlist
get_special_users_groups(Host) ->
lists:filter(
fun(Group) ->
end,
list_groups(Host)).
+%% Given two lists of groupnames and their options,
+%% return the list of displayed groups to the second list
displayed_groups(GroupsOpts, SelectedGroupsOpts) ->
DisplayedGroups =
lists:usort(
[G || G <- DisplayedGroups,
not lists:member(disabled, proplists:get_value(G, GroupsOpts, []))].
+%% Given a list of group names with options,
+%% for those that have @all@ in memberlist,
+%% get the list of groups displayed
get_special_displayed_groups(GroupsOpts) ->
Groups = lists:filter(
fun({_Group, Opts}) ->
end, GroupsOpts),
displayed_groups(GroupsOpts, Groups).
+%% Given a username and server, and a list of group names with options,
+%% for the list of groups of that server that user is member
+%% get the list of groups displayed
get_user_displayed_groups(LUser, LServer, GroupsOpts) ->
Groups = case catch mnesia:dirty_read(sr_user, {LUser, LServer}) of
Rs when is_list(Rs) ->
end,
displayed_groups(GroupsOpts, Groups).
+%% @doc Get the list of groups that are displayed to this user
get_user_displayed_groups(US) ->
Host = element(2, US),
DisplayedGroups1 =
_ -> true
end.
+
+%% @spec (Host::string(), {User::string(), Server::string()}, Group::string()) -> {atomic, ok}
add_user_to_group(Host, US, Group) ->
+ {LUser, LServer} = US,
+ %% Push this new user to members of groups where this group is displayed
+ push_user_to_displayed(LUser, LServer, Group, both),
+ %% Push members of groups that are displayed to this group
+ push_displayed_to_user(LUser, LServer, Group, Host, both),
R = #sr_user{us = US, group_host = {Group, Host}},
F = fun() ->
mnesia:write(R)
end,
mnesia:transaction(F).
+push_displayed_to_user(LUser, LServer, Group, Host, Subscription) ->
+ GroupsOpts = groups_with_opts(LServer),
+ GroupOpts = proplists:get_value(Group, GroupsOpts, []),
+ DisplayedGroups = proplists:get_value(displayed_groups, GroupOpts, []),
+ [push_members_to_user(LUser, LServer, DGroup, Host, Subscription) || DGroup <- DisplayedGroups].
+
remove_user_from_group(Host, US, Group) ->
GroupHost = {Group, Host},
R = #sr_user{us = US, group_host = GroupHost},
F = fun() ->
mnesia:delete_object(R)
end,
- mnesia:transaction(F).
+ Result = mnesia:transaction(F),
+ {LUser, LServer} = US,
+ %% Push removal of the old user to members of groups where the group that this user was members was displayed
+ push_user_to_displayed(LUser, LServer, Group, remove),
+ %% Push removal of members of groups that where displayed to the group which this user has left
+ push_displayed_to_user(LUser, LServer, Group, Host, remove),
+ Result.
+
+push_members_to_user(LUser, LServer, Group, Host, Subscription) ->
+ GroupsOpts = groups_with_opts(LServer),
+ GroupOpts = proplists:get_value(Group, GroupsOpts, []),
+ GroupName = proplists:get_value(name, GroupOpts, Group),
+ Members = get_group_users(Host, Group),
+ lists:foreach(
+ fun({U, S}) ->
+ push_roster_item(LUser, LServer, U, S, GroupName, Subscription)
+ end, Members).
+
+register_user(User, Server) ->
+ %% Get list of groups where this user is member
+ Groups = get_user_groups({User, Server}),
+ %% Push this user to members of groups where is displayed a group which this user is member
+ [push_user_to_displayed(User, Server, Group, both) || Group <- Groups].
+
+remove_user(User, Server) ->
+ push_user_to_members(User, Server, remove).
-user_registered(User, Server) ->
+push_user_to_members(User, Server, Subscription) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
GroupsOpts = groups_with_opts(LServer),
GroupName = proplists:get_value(name, GroupOpts, Group),
lists:foreach(
fun({U, S}) ->
- Item = #roster{usj = {U, S, {LUser, LServer, ""}},
- us = {U, S},
- jid = {LUser, LServer, ""},
- name = "",
- subscription = both,
- ask = none,
- groups = [GroupName]},
- push_item(U, S, jlib:make_jid("", S, ""), Item)
+ push_roster_item(U, S, LUser, LServer, GroupName, Subscription)
end, get_group_users(LUser, LServer, Group, GroupOpts))
end, lists:usort(SpecialGroups++UserGroups)).
+push_user_to_displayed(LUser, LServer, Group, Subscription) ->
+ GroupsOpts = groups_with_opts(LServer),
+ GroupOpts = proplists:get_value(Group, GroupsOpts, []),
+ GroupName = proplists:get_value(name, GroupOpts, Group),
+ DisplayedToGroupsOpts = displayed_to_groups(Group, LServer),
+ [push_user_to_group(LUser, LServer, GroupD, GroupName, Subscription) || {GroupD, _Opts} <- DisplayedToGroupsOpts].
+
+push_user_to_group(LUser, LServer, Group, GroupName, Subscription) ->
+ lists:foreach(
+ fun({U, S}) ->
+ push_roster_item(U, S, LUser, LServer, GroupName, Subscription)
+ end, get_group_users(LServer, Group)).
+
+%% Get list of groups to which this group is displayed
+displayed_to_groups(GroupName, LServer) ->
+ GroupsOpts = groups_with_opts(LServer),
+ lists:filter(
+ fun({_Group, Opts}) ->
+ lists:member(GroupName, proplists:get_value(displayed_groups, Opts, []))
+ end, GroupsOpts).
+
push_item(_User, _Server, _From, none) ->
ok;
push_item(User, Server, From, Item) ->
ejabberd_router:route(JID, JID, Stanza)
end, ejabberd_sm:get_user_resources(User, Server)).
+push_roster_item(User, Server, ContactU, ContactS, GroupName, Subscription) ->
+ Item = #roster{usj = {User, Server, {ContactU, ContactS, ""}},
+ us = {User, Server},
+ jid = {ContactU, ContactS, ""},
+ name = "",
+ subscription = Subscription,
+ ask = none,
+ groups = [GroupName]},
+ push_item(User, Server, jlib:make_jid("", Server, ""), Item).
+
item_to_xml(Item) ->
Attrs1 = [{"jid", jlib:jid_to_string(Item#roster.jid)}],
Attrs2 = case Item#roster.name of