mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-30 16:36:29 +01:00
Add support for '@online@' Shared Roster Group (thanks to Martin Langhoff)(EJAB-1391)
New version of the @online@ patch originally by Collabora. Notes: - the presence push is mediated via the group rather than per user - this may reduce memory footprint... _if_ ejabberd has some smart optimisation in that codepath - it assumes that any group with membership @online@ _displays_ online as well -- this is a simplification and breaks the decoupling that ejabberd has in this regard.
This commit is contained in:
parent
61e4fde247
commit
e0bda563e6
@ -4098,11 +4098,13 @@ has a unique identification and the following parameters:
|
|||||||
\item[Name] The name of the group, which will be displayed in the roster.
|
\item[Name] The name of the group, which will be displayed in the roster.
|
||||||
\item[Description] The description of the group. This parameter does not affect
|
\item[Description] The description of the group. This parameter does not affect
|
||||||
anything.
|
anything.
|
||||||
\item[Members] A list of full JIDs of group members, entered one per line in
|
\item[Members] A list of JIDs of group members, entered one per line in
|
||||||
the Web Admin.
|
the Web Admin.
|
||||||
To put as members all the registered users in the virtual hosts,
|
The special member directive \term{@all@}
|
||||||
you can use the special directive: @all@.
|
represents all the registered users in the virtual host;
|
||||||
Note that this directive is designed for a small server with just a few hundred users.
|
which is only recommended for a small server with just a few hundred users.
|
||||||
|
The special member directive \term{@online@}
|
||||||
|
represents the online users in the virtual host.
|
||||||
\item[Displayed groups] A list of groups that will be in the rosters of this
|
\item[Displayed groups] A list of groups that will be in the rosters of this
|
||||||
group's members.
|
group's members.
|
||||||
\end{description}
|
\end{description}
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
process_item/2,
|
process_item/2,
|
||||||
in_subscription/6,
|
in_subscription/6,
|
||||||
out_subscription/4,
|
out_subscription/4,
|
||||||
|
user_available/1,
|
||||||
|
unset_presence/4,
|
||||||
register_user/2,
|
register_user/2,
|
||||||
remove_user/2,
|
remove_user/2,
|
||||||
list_groups/1,
|
list_groups/1,
|
||||||
@ -87,6 +89,10 @@ start(Host, _Opts) ->
|
|||||||
?MODULE, get_jid_info, 70),
|
?MODULE, get_jid_info, 70),
|
||||||
ejabberd_hooks:add(roster_process_item, HostB,
|
ejabberd_hooks:add(roster_process_item, HostB,
|
||||||
?MODULE, process_item, 50),
|
?MODULE, process_item, 50),
|
||||||
|
ejabberd_hooks:add(user_available_hook, HostB,
|
||||||
|
?MODULE, user_available, 50),
|
||||||
|
ejabberd_hooks:add(unset_presence_hook, HostB,
|
||||||
|
?MODULE, unset_presence, 50),
|
||||||
ejabberd_hooks:add(register_user, HostB,
|
ejabberd_hooks:add(register_user, HostB,
|
||||||
?MODULE, register_user, 50),
|
?MODULE, register_user, 50),
|
||||||
ejabberd_hooks:add(anonymous_purge_hook, HostB,
|
ejabberd_hooks:add(anonymous_purge_hook, HostB,
|
||||||
@ -114,6 +120,10 @@ stop(Host) ->
|
|||||||
?MODULE, get_jid_info, 70),
|
?MODULE, get_jid_info, 70),
|
||||||
ejabberd_hooks:delete(roster_process_item, HostB,
|
ejabberd_hooks:delete(roster_process_item, HostB,
|
||||||
?MODULE, process_item, 50),
|
?MODULE, process_item, 50),
|
||||||
|
ejabberd_hooks:delete(user_available_hook, HostB,
|
||||||
|
?MODULE, user_available, 50),
|
||||||
|
ejabberd_hooks:delete(unset_presence_hook, HostB,
|
||||||
|
?MODULE, unset_presence, 50),
|
||||||
ejabberd_hooks:delete(register_user, HostB,
|
ejabberd_hooks:delete(register_user, HostB,
|
||||||
?MODULE, register_user, 50),
|
?MODULE, register_user, 50),
|
||||||
ejabberd_hooks:delete(anonymous_purge_hook, HostB,
|
ejabberd_hooks:delete(anonymous_purge_hook, HostB,
|
||||||
@ -128,7 +138,6 @@ get_user_roster(Items, {U, S}) when is_binary(U) ->
|
|||||||
get_user_roster(Items, {binary_to_list(U), binary_to_list(S)});
|
get_user_roster(Items, {binary_to_list(U), binary_to_list(S)});
|
||||||
get_user_roster(Items, US) ->
|
get_user_roster(Items, US) ->
|
||||||
{U, S} = US,
|
{U, S} = US,
|
||||||
USB = {list_to_binary(U), list_to_binary(S)},
|
|
||||||
DisplayedGroups = get_user_displayed_groups(US),
|
DisplayedGroups = get_user_displayed_groups(US),
|
||||||
%% Get shared roster users in all groups and remove self:
|
%% Get shared roster users in all groups and remove self:
|
||||||
SRUsers =
|
SRUsers =
|
||||||
@ -136,9 +145,9 @@ get_user_roster(Items, US) ->
|
|||||||
fun(Group, Acc1) ->
|
fun(Group, Acc1) ->
|
||||||
GroupName = get_group_name(S, Group),
|
GroupName = get_group_name(S, Group),
|
||||||
lists:foldl(
|
lists:foldl(
|
||||||
fun(UserServerB, Acc2) ->
|
fun(UserServer, Acc2) ->
|
||||||
if UserServerB == USB -> Acc2;
|
if UserServer == US -> Acc2;
|
||||||
true -> dict:append(UserServerB,
|
true -> dict:append(UserServer,
|
||||||
GroupName,
|
GroupName,
|
||||||
Acc2)
|
Acc2)
|
||||||
end
|
end
|
||||||
@ -506,27 +515,47 @@ get_group_opt(Host, Group, Opt, Default) ->
|
|||||||
Default
|
Default
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @spec(Host::string(), Group::string()) -> [{Username::binary(), Server::binary()}]
|
get_online_users(Host) ->
|
||||||
|
lists:usort([{binary_to_list(U), binary_to_list(S)}
|
||||||
|
|| {U, S, _} <-
|
||||||
|
ejabberd_sm:get_vh_session_list(list_to_binary(Host))]).
|
||||||
|
|
||||||
|
%% @spec(Host::string(), Group::string()) -> [{Username::string(), Server::string()}]
|
||||||
get_group_users(HostB, Group) when is_binary(HostB) ->
|
get_group_users(HostB, Group) when is_binary(HostB) ->
|
||||||
get_group_users(binary_to_list(HostB), Group);
|
get_group_users(binary_to_list(HostB), Group);
|
||||||
|
|
||||||
get_group_users(Host, Group) ->
|
get_group_users(Host, Group) ->
|
||||||
case get_group_opt(Host, Group, all_users, false) of
|
case get_group_opt(Host, Group, all_users, false) of
|
||||||
true ->
|
true ->
|
||||||
ejabberd_auth:get_vh_registered_users(Host);
|
ejabberd_auth:get_vh_registered_users(Host);
|
||||||
false ->
|
false ->
|
||||||
[]
|
[]
|
||||||
end ++ get_group_explicit_users(Host, Group).
|
end ++
|
||||||
|
case get_group_opt(Host, Group, online_users, false) of
|
||||||
|
true ->
|
||||||
|
get_online_users(Host);
|
||||||
|
false ->
|
||||||
|
[]
|
||||||
|
end ++
|
||||||
|
get_group_explicit_users(Host, Group).
|
||||||
|
|
||||||
%% @spec(User::any(), Host::string(), Group::string(), GroupOpts) -> [{Username::binary(), Server::binary()}]
|
%% @spec(Host::string(), Group::string(), GroupOpts) -> [{Username::binary(), Server::binary()}]
|
||||||
get_group_users(User, HostB, Group, GroupOpts) when is_binary(HostB) ->
|
get_group_users(HostB, Group, GroupOpts) when is_binary(HostB) ->
|
||||||
get_group_users(User, binary_to_list(HostB), Group, GroupOpts);
|
get_group_users(binary_to_list(HostB), Group, GroupOpts);
|
||||||
get_group_users(_User, Host, Group, GroupOpts) ->
|
get_group_users(Host, Group, GroupOpts) ->
|
||||||
case proplists:get_value(all_users, GroupOpts, false) of
|
case proplists:get_value(all_users, GroupOpts, false) of
|
||||||
true ->
|
true ->
|
||||||
ejabberd_auth:get_vh_registered_users(Host);
|
ejabberd_auth:get_vh_registered_users(Host);
|
||||||
false ->
|
false ->
|
||||||
[]
|
[]
|
||||||
end ++ get_group_explicit_users(Host, Group).
|
end ++
|
||||||
|
case proplists:get_value(online_users, GroupOpts, false) of
|
||||||
|
true ->
|
||||||
|
get_online_users(Host);
|
||||||
|
false ->
|
||||||
|
[]
|
||||||
|
end ++
|
||||||
|
get_group_explicit_users(Host, Group).
|
||||||
|
|
||||||
%% @spec (Host::string(), Group::string()) -> [{User::string(), Server::string()}]
|
%% @spec (Host::string(), Group::string()) -> [{User::string(), Server::string()}]
|
||||||
get_group_explicit_users(Host, Group) ->
|
get_group_explicit_users(Host, Group) ->
|
||||||
@ -545,13 +574,22 @@ get_group_name(Host, Group) ->
|
|||||||
get_group_opt(Host, Group, name, Group).
|
get_group_opt(Host, Group, name, Group).
|
||||||
|
|
||||||
%% @spec(Host::string)
|
%% @spec(Host::string)
|
||||||
%% @doc Get list of names of groups that have @all@ in the memberlist
|
%% @doc Get list of names of groups that have @all@ or @online@ in the memberlist
|
||||||
get_special_users_groups(HostB) when is_binary(HostB)->
|
get_special_users_groups(HostB) when is_binary(HostB)->
|
||||||
get_special_users_groups(binary_to_list(HostB));
|
get_special_users_groups(binary_to_list(HostB));
|
||||||
get_special_users_groups(Host) ->
|
get_special_users_groups(Host) ->
|
||||||
lists:filter(
|
lists:filter(
|
||||||
fun(Group) ->
|
fun(Group) ->
|
||||||
get_group_opt(Host, Group, all_users, false)
|
get_group_opt(Host, Group, all_users, false)
|
||||||
|
orelse get_group_opt(Host, Group, online_users, false)
|
||||||
|
end,
|
||||||
|
list_groups(Host)).
|
||||||
|
|
||||||
|
%% Get list of names of groups that have @online@ in the memberlist
|
||||||
|
get_special_users_groups_online(Host) ->
|
||||||
|
lists:filter(
|
||||||
|
fun(Group) ->
|
||||||
|
get_group_opt(Host, Group, online_users, false)
|
||||||
end,
|
end,
|
||||||
list_groups(Host)).
|
list_groups(Host)).
|
||||||
|
|
||||||
@ -712,13 +750,17 @@ push_user_to_members(User, Server, Subscription) ->
|
|||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun({U, S}) ->
|
fun({U, S}) ->
|
||||||
push_roster_item(U, S, LUser, LServer, GroupName, Subscription)
|
push_roster_item(U, S, LUser, LServer, GroupName, Subscription)
|
||||||
end, get_group_users(LUser, LServer, Group, GroupOpts))
|
end, get_group_users(LServer, Group, GroupOpts))
|
||||||
end, lists:usort(SpecialGroups++UserGroups))
|
end, lists:usort(SpecialGroups++UserGroups))
|
||||||
catch
|
catch
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
push_user_to_displayed(User, Server, Group, Subscription) when is_binary(User) ->
|
||||||
|
LUser = binary_to_list(User),
|
||||||
|
LServer = binary_to_list(Server),
|
||||||
|
push_user_to_displayed(LUser, LServer, Group, Subscription);
|
||||||
push_user_to_displayed(LUser, LServer, Group, Subscription) ->
|
push_user_to_displayed(LUser, LServer, Group, Subscription) ->
|
||||||
GroupsOpts = groups_with_opts(LServer),
|
GroupsOpts = groups_with_opts(LServer),
|
||||||
GroupOpts = proplists:get_value(Group, GroupsOpts, []),
|
GroupOpts = proplists:get_value(Group, GroupsOpts, []),
|
||||||
@ -728,7 +770,8 @@ push_user_to_displayed(LUser, LServer, Group, Subscription) ->
|
|||||||
|
|
||||||
push_user_to_group(LUser, LServer, Group, GroupName, Subscription) ->
|
push_user_to_group(LUser, LServer, Group, GroupName, Subscription) ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun({U, S}) ->
|
fun({U, S}) when (U == LUser) and (S == LServer) -> ok;
|
||||||
|
({U, S}) ->
|
||||||
push_roster_item(U, S, LUser, LServer, GroupName, Subscription)
|
push_roster_item(U, S, LUser, LServer, GroupName, Subscription)
|
||||||
end, get_group_users(LServer, Group)).
|
end, get_group_users(LServer, Group)).
|
||||||
|
|
||||||
@ -772,6 +815,54 @@ push_roster_item(User, Server, ContactU, ContactS, GroupName, Subscription) ->
|
|||||||
groups = [GroupName]},
|
groups = [GroupName]},
|
||||||
push_item(User, Server, exmpp_jid:make(Server), Item).
|
push_item(User, Server, exmpp_jid:make(Server), Item).
|
||||||
|
|
||||||
|
user_available(New) ->
|
||||||
|
LUser = exmpp_jid:node(New),
|
||||||
|
LServer = exmpp_jid:domain(New),
|
||||||
|
Resources = ejabberd_sm:get_user_resources(LUser, LServer),
|
||||||
|
?DEBUG("user_available for ~p @ ~p (~p resources)",
|
||||||
|
[LUser, LServer, length(Resources)]),
|
||||||
|
case length(Resources) of
|
||||||
|
%% first session for this user
|
||||||
|
1 ->
|
||||||
|
%% This is a simplification - we ignore he 'display'
|
||||||
|
%% property - @online@ is always reflective.
|
||||||
|
OnlineGroups = get_special_users_groups_online(binary_to_list(LServer)),
|
||||||
|
lists:foreach(
|
||||||
|
fun(OG) ->
|
||||||
|
?DEBUG("user_available: pushing ~p @ ~p grp ~p",
|
||||||
|
[LUser, LServer, OG ]),
|
||||||
|
push_user_to_displayed(LUser, LServer, OG, both)
|
||||||
|
end, OnlineGroups);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
unset_presence(User, Server, Resource, Status) ->
|
||||||
|
LUser = binary_to_list(User),
|
||||||
|
LServer = binary_to_list(Server),
|
||||||
|
Resources = ejabberd_sm:get_user_resources(User, Server),
|
||||||
|
?DEBUG("unset_presence for ~p @ ~p / ~p -> ~p (~p resources)",
|
||||||
|
[LUser, LServer, Resource, Status, length(Resources)]),
|
||||||
|
%% if user has no resources left...
|
||||||
|
case length(Resources) of
|
||||||
|
0 ->
|
||||||
|
%% This is a simplification - we ignore he 'display'
|
||||||
|
%% property - @online@ is always reflective.
|
||||||
|
OnlineGroups = get_special_users_groups_online(LServer),
|
||||||
|
%% for each of these groups...
|
||||||
|
lists:foreach(
|
||||||
|
fun(OG) ->
|
||||||
|
%% Push removal of the old user to members of groups
|
||||||
|
%% where the group that this uwas members was displayed
|
||||||
|
push_user_to_displayed(LUser, LServer, OG, remove),
|
||||||
|
%% Push removal of members of groups that where
|
||||||
|
%% displayed to the group which thiuser has left
|
||||||
|
push_displayed_to_user(LUser, LServer, OG, LServer,remove)
|
||||||
|
end, OnlineGroups);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
%%---------------------
|
%%---------------------
|
||||||
%% Web Admin
|
%% Web Admin
|
||||||
%%---------------------
|
%%---------------------
|
||||||
@ -874,6 +965,7 @@ shared_roster_group(Host, Group, Query, Lang) ->
|
|||||||
Name = get_opt(GroupOpts, name, ""),
|
Name = get_opt(GroupOpts, name, ""),
|
||||||
Description = get_opt(GroupOpts, description, ""),
|
Description = get_opt(GroupOpts, description, ""),
|
||||||
AllUsers = get_opt(GroupOpts, all_users, false),
|
AllUsers = get_opt(GroupOpts, all_users, false),
|
||||||
|
OnlineUsers = get_opt(GroupOpts, online_users, false),
|
||||||
%%Disabled = false,
|
%%Disabled = false,
|
||||||
DisplayedGroups = get_opt(GroupOpts, displayed_groups, []),
|
DisplayedGroups = get_opt(GroupOpts, displayed_groups, []),
|
||||||
Members = mod_shared_roster:get_group_explicit_users(Host, Group),
|
Members = mod_shared_roster:get_group_explicit_users(Host, Group),
|
||||||
@ -883,7 +975,14 @@ shared_roster_group(Host, Group, Query, Lang) ->
|
|||||||
"@all@\n";
|
"@all@\n";
|
||||||
true ->
|
true ->
|
||||||
[]
|
[]
|
||||||
end ++ [[us_to_list(Member), $\n] || Member <- Members],
|
end ++
|
||||||
|
if
|
||||||
|
OnlineUsers ->
|
||||||
|
"@online@\n";
|
||||||
|
true ->
|
||||||
|
[]
|
||||||
|
end ++
|
||||||
|
[[us_to_list(Member), $\n] || Member <- Members],
|
||||||
FDisplayedGroups = [[DG, $\n] || DG <- DisplayedGroups],
|
FDisplayedGroups = [[DG, $\n] || DG <- DisplayedGroups],
|
||||||
DescNL = length(re:split(Description, "\n", [{return, list}])),
|
DescNL = length(re:split(Description, "\n", [{return, list}])),
|
||||||
FGroup =
|
FGroup =
|
||||||
@ -972,6 +1071,8 @@ shared_roster_group_parse_query(Host, Group, Query) ->
|
|||||||
case SJID of
|
case SJID of
|
||||||
"@all@" ->
|
"@all@" ->
|
||||||
USs;
|
USs;
|
||||||
|
"@online@" ->
|
||||||
|
USs;
|
||||||
_ ->
|
_ ->
|
||||||
try
|
try
|
||||||
JID = exmpp_jid:parse(SJID),
|
JID = exmpp_jid:parse(SJID),
|
||||||
@ -987,10 +1088,15 @@ shared_roster_group_parse_query(Host, Group, Query) ->
|
|||||||
true -> [{all_users, true}];
|
true -> [{all_users, true}];
|
||||||
false -> []
|
false -> []
|
||||||
end,
|
end,
|
||||||
|
OnlineUsersOpt =
|
||||||
|
case lists:member("@online@", SJIDs) of
|
||||||
|
true -> [{online_users, true}];
|
||||||
|
false -> []
|
||||||
|
end,
|
||||||
|
|
||||||
mod_shared_roster:set_group_opts(
|
mod_shared_roster:set_group_opts(
|
||||||
Host, Group,
|
Host, Group,
|
||||||
NameOpt ++ DispGroupsOpt ++ DescriptionOpt ++ AllUsersOpt),
|
NameOpt ++ DispGroupsOpt ++ DescriptionOpt ++ AllUsersOpt ++ OnlineUsersOpt),
|
||||||
|
|
||||||
if
|
if
|
||||||
NewMembers == error -> error;
|
NewMembers == error -> error;
|
||||||
|
Loading…
Reference in New Issue
Block a user