diff options
Diffstat (limited to 'src/mod_shared_roster.erl')
-rw-r--r-- | src/mod_shared_roster.erl | 510 |
1 files changed, 208 insertions, 302 deletions
diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index b472e1aab..0ce97d1ca 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -5,7 +5,7 @@ %%% Created : 5 Mar 2005 by Alexey Shchepin <alexey@process-one.net> %%% %%% -%%% ejabberd, Copyright (C) 2002-2016 ProcessOne +%%% ejabberd, Copyright (C) 2002-2019 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -29,22 +29,21 @@ -behaviour(gen_mod). --export([start/2, stop/1, item_to_xml/1, export/1, - import/1, webadmin_menu/3, webadmin_page/3, - get_user_roster/2, get_subscription_lists/3, - get_jid_info/4, import/3, process_item/2, - in_subscription/6, out_subscription/4, user_available/1, +-export([start/2, stop/1, reload/3, export/1, + import_info/0, webadmin_menu/3, webadmin_page/3, + get_user_roster/2, + get_jid_info/4, import/5, process_item/2, import_start/2, + in_subscription/2, out_subscription/1, c2s_self_presence/1, unset_presence/4, register_user/2, remove_user/2, list_groups/1, create_group/2, create_group/3, delete_group/2, get_group_opts/2, set_group_opts/3, get_group_users/2, get_group_explicit_users/2, is_user_in_group/3, add_user_to_group/3, opts_to_binary/1, - remove_user_from_group/3, mod_opt_type/1, depends/2]). + remove_user_from_group/3, mod_opt_type/1, mod_options/1, depends/2]). --include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_roster.hrl"). @@ -54,9 +53,11 @@ -include("mod_shared_roster.hrl"). +-include("translate.hrl"). + -type group_options() :: [{atom(), any()}]. -callback init(binary(), gen_mod:opts()) -> any(). --callback import(binary(), #sr_user{} | #sr_group{}) -> ok | pass. +-callback import(binary(), binary(), [binary()]) -> ok. -callback list_groups(binary()) -> [binary()]. -callback groups_with_opts(binary()) -> [{binary(), group_options()}]. -callback create_group(binary(), binary(), group_options()) -> {atomic, any()}. @@ -68,11 +69,11 @@ -callback get_user_displayed_groups(binary(), binary(), group_options()) -> [{binary(), group_options()}]. -callback is_user_in_group({binary(), binary()}, binary(), binary()) -> boolean(). --callback add_user_to_group(binary(), {binary(), binary()}, binary()) -> {atomic, any()}. +-callback add_user_to_group(binary(), {binary(), binary()}, binary()) -> any(). -callback remove_user_from_group(binary(), {binary(), binary()}, binary()) -> {atomic, any()}. start(Host, Opts) -> - Mod = gen_mod:db_mod(Host, Opts, ?MODULE), + Mod = gen_mod:db_mod(Opts, ?MODULE), Mod:init(Host, Opts), ejabberd_hooks:add(webadmin_menu_host, Host, ?MODULE, webadmin_menu, 70), @@ -84,20 +85,16 @@ start(Host, Opts) -> ?MODULE, in_subscription, 30), ejabberd_hooks:add(roster_out_subscription, Host, ?MODULE, out_subscription, 30), - ejabberd_hooks:add(roster_get_subscription_lists, Host, - ?MODULE, get_subscription_lists, 70), ejabberd_hooks:add(roster_get_jid_info, Host, ?MODULE, get_jid_info, 70), ejabberd_hooks:add(roster_process_item, Host, ?MODULE, process_item, 50), - ejabberd_hooks:add(user_available_hook, Host, ?MODULE, - user_available, 50), + ejabberd_hooks:add(c2s_self_presence, Host, ?MODULE, + c2s_self_presence, 50), ejabberd_hooks:add(unset_presence_hook, Host, ?MODULE, unset_presence, 50), ejabberd_hooks:add(register_user, Host, ?MODULE, register_user, 50), - ejabberd_hooks:add(anonymous_purge_hook, Host, ?MODULE, - remove_user, 50), ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50). @@ -112,29 +109,34 @@ stop(Host) -> ?MODULE, in_subscription, 30), ejabberd_hooks:delete(roster_out_subscription, Host, ?MODULE, out_subscription, 30), - ejabberd_hooks:delete(roster_get_subscription_lists, - Host, ?MODULE, get_subscription_lists, 70), ejabberd_hooks:delete(roster_get_jid_info, Host, ?MODULE, get_jid_info, 70), ejabberd_hooks:delete(roster_process_item, Host, ?MODULE, process_item, 50), - ejabberd_hooks:delete(user_available_hook, Host, - ?MODULE, user_available, 50), + ejabberd_hooks:delete(c2s_self_presence, Host, + ?MODULE, c2s_self_presence, 50), ejabberd_hooks:delete(unset_presence_hook, Host, ?MODULE, unset_presence, 50), ejabberd_hooks:delete(register_user, Host, ?MODULE, register_user, 50), - ejabberd_hooks:delete(anonymous_purge_hook, Host, - ?MODULE, remove_user, 50), ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50). - %%ejabberd_hooks:delete(remove_user, Host, - %% ?MODULE, remove_user, 50), + +reload(Host, NewOpts, OldOpts) -> + NewMod = gen_mod:db_mod(NewOpts, ?MODULE), + OldMod = gen_mod:db_mod(OldOpts, ?MODULE), + if NewMod /= OldMod -> + NewMod:init(Host, NewOpts); + true -> + ok + end, + ok. depends(_Host, _Opts) -> []. +-spec get_user_roster([#roster{}], {binary(), binary()}) -> [#roster{}]. get_user_roster(Items, US) -> {U, S} = US, DisplayedGroups = get_user_displayed_groups(US), @@ -159,10 +161,12 @@ get_user_roster(Items, US) -> case dict:find(US1, SRUsers1) of - {ok, _GroupNames} -> + {ok, GroupNames} -> {Item#roster{subscription = both, + groups = + Item#roster.groups ++ GroupNames, ask = none}, dict:erase(US1, @@ -172,56 +176,37 @@ get_user_roster(Items, US) -> end end, SRUsers, Items), - ModVcard = get_vcard_module(S), SRItems = [#roster{usj = {U, S, {U1, S1, <<"">>}}, us = US, jid = {U1, S1, <<"">>}, - name = get_rosteritem_name(ModVcard, U1, S1), + name = get_rosteritem_name(U1, S1), subscription = both, ask = none, groups = GroupNames} || {{U1, S1}, GroupNames} <- dict:to_list(SRUsersRest)], SRItems ++ NewItems1. -get_vcard_module(Server) -> - Modules = gen_mod:loaded_modules(Server), - [M - || M <- Modules, - (M == mod_vcard) or (M == mod_vcard_ldap)]. - -get_rosteritem_name([], _, _) -> <<"">>; -get_rosteritem_name([ModVcard], U, S) -> - From = jid:make(<<"">>, S, jlib:atom_to_binary(?MODULE)), - To = jid:make(U, S, <<"">>), - case lists:member(To#jid.lserver, ?MYHOSTS) of +get_rosteritem_name(U, S) -> + case gen_mod:is_loaded(S, mod_vcard) of true -> - IQ = {iq, <<"">>, get, <<"vcard-temp">>, <<"">>, - #xmlel{name = <<"vCard">>, - attrs = [{<<"xmlns">>, <<"vcard-temp">>}], - children = []}}, - IQ_Vcard = ModVcard:process_sm_iq(From, To, IQ), - case catch get_rosteritem_name_vcard(IQ_Vcard#iq.sub_el) of - {'EXIT', Err} -> - ?ERROR_MSG("Error found when trying to get the " - "vCard of ~s@~s in ~p:~n ~p", - [U, S, ModVcard, Err]), - <<"">>; - NickName -> - NickName - end; + SubEls = mod_vcard:get_vcard(U, S), + get_rosteritem_name_vcard(SubEls); false -> <<"">> end. -get_rosteritem_name_vcard([]) -> <<"">>; -get_rosteritem_name_vcard([Vcard]) -> +-spec get_rosteritem_name_vcard([xmlel()]) -> binary(). +get_rosteritem_name_vcard([Vcard|_]) -> case fxml:get_path_s(Vcard, [{elem, <<"NICKNAME">>}, cdata]) of <<"">> -> fxml:get_path_s(Vcard, [{elem, <<"FN">>}, cdata]); Nickname -> Nickname - end. + end; +get_rosteritem_name_vcard(_) -> + <<"">>. %% This function rewrites the roster entries when moving or renaming %% them in the user contact list. +-spec process_item(#roster{}, binary()) -> #roster{}. process_item(RosterItem, Host) -> USFrom = {UserFrom, ServerFrom} = RosterItem#roster.us, {UserTo, ServerTo, ResourceTo} = RosterItem#roster.jid, @@ -251,14 +236,11 @@ process_item(RosterItem, Host) -> %% If it doesn't, then remove this user from any %% existing roster groups. [] -> - mod_roster:out_subscription(UserTo, ServerTo, - jid:make(UserFrom, ServerFrom, - <<"">>), - unsubscribe), - mod_roster:in_subscription(aaaa, UserFrom, ServerFrom, - jid:make(UserTo, ServerTo, - <<"">>), - unsubscribe, <<"">>), + Pres = #presence{from = jid:make(UserTo, ServerTo), + to = jid:make(UserFrom, ServerFrom), + type = unsubscribe}, + mod_roster:out_subscription(Pres), + mod_roster:in_subscription(false, Pres), RosterItem#roster{subscription = both, ask = none}; %% If so, it means the user wants to add that contact %% to his personal roster @@ -281,54 +263,40 @@ set_new_rosteritems(UserFrom, ServerFrom, UserTo, RIFrom = build_roster_record(UserFrom, ServerFrom, UserTo, ServerTo, NameTo, GroupsFrom), set_item(UserFrom, ServerFrom, ResourceTo, RIFrom), - JIDTo = jid:make(UserTo, ServerTo, <<"">>), - JIDFrom = jid:make(UserFrom, ServerFrom, <<"">>), + JIDTo = jid:make(UserTo, ServerTo), + JIDFrom = jid:make(UserFrom, ServerFrom), RITo = build_roster_record(UserTo, ServerTo, UserFrom, ServerFrom, UserFrom, []), set_item(UserTo, ServerTo, <<"">>, RITo), - mod_roster:out_subscription(UserFrom, ServerFrom, JIDTo, - subscribe), - mod_roster:in_subscription(aaa, UserTo, ServerTo, - JIDFrom, subscribe, <<"">>), - mod_roster:out_subscription(UserTo, ServerTo, JIDFrom, - subscribed), - mod_roster:in_subscription(aaa, UserFrom, ServerFrom, - JIDTo, subscribed, <<"">>), - mod_roster:out_subscription(UserTo, ServerTo, JIDFrom, - subscribe), - mod_roster:in_subscription(aaa, UserFrom, ServerFrom, - JIDTo, subscribe, <<"">>), - mod_roster:out_subscription(UserFrom, ServerFrom, JIDTo, - subscribed), - mod_roster:in_subscription(aaa, UserTo, ServerTo, - JIDFrom, subscribed, <<"">>), + mod_roster:out_subscription( + #presence{from = JIDFrom, to = JIDTo, type = subscribe}), + mod_roster:in_subscription( + false, #presence{to = JIDTo, from = JIDFrom, type = subscribe}), + mod_roster:out_subscription( + #presence{from = JIDTo, to = JIDFrom, type = subscribed}), + mod_roster:in_subscription( + false, #presence{to = JIDFrom, from = JIDTo, type = subscribed}), + mod_roster:out_subscription( + #presence{from = JIDTo, to = JIDFrom, type = subscribe}), + mod_roster:in_subscription( + false, #presence{to = JIDFrom, from = JIDTo, type = subscribe}), + mod_roster:out_subscription( + #presence{from = JIDFrom, to = JIDTo, type = subscribed}), + mod_roster:in_subscription( + false, #presence{to = JIDTo, from = JIDFrom, type = subscribed}), RIFrom. set_item(User, Server, Resource, Item) -> - ResIQ = #iq{type = set, xmlns = ?NS_ROSTER, - id = <<"push", (randoms:get_string())/binary>>, - sub_el = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_ROSTER}], - children = [mod_roster:item_to_xml(Item)]}]}, - ejabberd_router:route(jid:make(User, Server, - Resource), - jid:make(<<"">>, Server, <<"">>), - jlib:iq_to_xml(ResIQ)). - -get_subscription_lists({F, T}, User, Server) -> - LUser = jid:nodeprep(User), - LServer = jid: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, + ResIQ = #iq{from = jid:make(User, Server, Resource), + to = jid:make(Server), + type = set, id = <<"push", (p1_rand:get_string())/binary>>, + sub_els = [#roster_query{ + items = [mod_roster:encode_item(Item)]}]}, + ejabberd_router:route(ResIQ). + +-spec get_jid_info({subscription(), ask(), [binary()]}, binary(), binary(), jid()) + -> {subscription(), ask(), [binary()]}. +get_jid_info({Subscription, Ask, Groups}, User, Server, JID) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), @@ -337,10 +305,10 @@ get_jid_info({Subscription, Groups}, User, Server, US1 = {U1, S1}, DisplayedGroups = get_user_displayed_groups(US), SRUsers = lists:foldl(fun (Group, Acc1) -> + GroupName = get_group_name(LServer, Group), lists:foldl(fun (User1, Acc2) -> dict:append(User1, - get_group_name(LServer, - Group), + GroupName, Acc2) end, Acc1, @@ -352,27 +320,26 @@ get_jid_info({Subscription, Groups}, User, Server, NewGroups = if Groups == [] -> GroupNames; true -> Groups end, - {both, NewGroups}; - error -> {Subscription, Groups} + {both, none, NewGroups}; + error -> {Subscription, Ask, Groups} end. -in_subscription(Acc, User, Server, JID, Type, - _Reason) -> +-spec in_subscription(boolean(), presence()) -> boolean(). +in_subscription(Acc, #presence{to = To, from = JID, type = Type}) -> + #jid{user = User, server = Server} = To, process_subscription(in, User, Server, JID, Type, Acc). -out_subscription(UserFrom, ServerFrom, JIDTo, - unsubscribed) -> - #jid{luser = UserTo, lserver = ServerTo} = JIDTo, - JIDFrom = jid:make(UserFrom, ServerFrom, <<"">>), - mod_roster:out_subscription(UserTo, ServerTo, JIDFrom, - unsubscribe), - mod_roster:in_subscription(aaaa, UserFrom, ServerFrom, - JIDTo, unsubscribe, <<"">>), - process_subscription(out, UserFrom, ServerFrom, JIDTo, - unsubscribed, false); -out_subscription(User, Server, JID, Type) -> - process_subscription(out, User, Server, JID, Type, - false). +-spec out_subscription(presence()) -> boolean(). +out_subscription(#presence{from = From, to = To, type = unsubscribed} = Pres) -> + #jid{user = User, server = Server} = From, + mod_roster:out_subscription(Pres#presence{type = unsubscribe}), + mod_roster:in_subscription(false, xmpp:set_from_to( + Pres#presence{type = unsubscribe}, + To, From)), + process_subscription(out, User, Server, To, unsubscribed, false); +out_subscription(#presence{from = From, to = To, type = Type}) -> + #jid{user = User, server = Server} = From, + process_subscription(out, User, Server, To, Type, false). process_subscription(Direction, User, Server, JID, _Type, Acc) -> @@ -453,7 +420,7 @@ get_online_users(Host) -> get_group_users(Host1, Group1) -> {Host, Group} = split_grouphost(Host1, Group1), case get_group_opt(Host, Group, all_users, false) of - true -> ejabberd_auth:get_vh_registered_users(Host); + true -> ejabberd_auth:get_users(Host); false -> [] end ++ @@ -465,7 +432,7 @@ get_group_users(Host1, Group1) -> get_group_users(Host, Group, GroupOpts) -> case proplists:get_value(all_users, GroupOpts, false) of - true -> ejabberd_auth:get_vh_registered_users(Host); + true -> ejabberd_auth:get_users(Host); false -> [] end ++ @@ -486,18 +453,24 @@ get_group_name(Host1, Group1) -> %% Get list of names of groups that have @all@/@online@/etc in the memberlist get_special_users_groups(Host) -> - lists:filter(fun (Group) -> - get_group_opt(Host, Group, all_users, false) orelse - get_group_opt(Host, Group, online_users, false) - end, - list_groups(Host)). + lists:filtermap(fun ({Group, Opts}) -> + case proplists:get_value(all_users, Opts, false) orelse + proplists:get_value(online_users, Opts, false) of + true -> {true, Group}; + false -> false + end + end, + groups_with_opts(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, - list_groups(Host)). + lists:filtermap(fun ({Group, Opts}) -> + case proplists:get_value(online_users, Opts, false) of + true -> {true, Group}; + false -> false + end + end, + groups_with_opts(Host)). %% Given two lists of groupnames and their options, %% return the list of displayed groups to the second list @@ -569,26 +542,32 @@ is_user_in_group(US, Group, Host) -> true end. -%% @spec (Host::string(), {User::string(), Server::string()}, Group::string()) -> {atomic, ok} +%% @spec (Host::string(), {User::string(), Server::string()}, Group::string()) -> {atomic, ok} | error add_user_to_group(Host, US, Group) -> + {_LUser, LServer} = US, + case lists:member(LServer, ejabberd_config:get_option(hosts)) of + true -> add_user_to_group2(Host, US, Group); + false -> + ?INFO_MSG("Attempted adding to shared roster user of inexistent vhost ~ts", [LServer]), + error + end. +add_user_to_group2(Host, US, Group) -> {LUser, LServer} = US, case ejabberd_regexp:run(LUser, <<"^@.+@\$">>) of match -> - GroupOpts = (?MODULE):get_group_opts(Host, Group), + GroupOpts = mod_shared_roster:get_group_opts(Host, Group), MoreGroupOpts = case LUser of <<"@all@">> -> [{all_users, true}]; <<"@online@">> -> [{online_users, true}]; _ -> [] end, - (?MODULE):set_group_opts(Host, Group, + mod_shared_roster:set_group_opts(Host, Group, GroupOpts ++ MoreGroupOpts); nomatch -> DisplayedToGroups = displayed_to_groups(Group, Host), DisplayedGroups = get_displayed_groups(Group, LServer), push_user_to_displayed(LUser, LServer, Group, Host, both, DisplayedToGroups), push_displayed_to_user(LUser, LServer, Host, both, DisplayedGroups), - broadcast_user_to_displayed(LUser, LServer, Host, both, DisplayedToGroups), - broadcast_displayed_to_user(LUser, LServer, Host, both, DisplayedGroups), Mod = gen_mod:db_mod(Host, ?MODULE), Mod:add_user_to_group(Host, US, Group) end. @@ -598,11 +577,6 @@ get_displayed_groups(Group, LServer) -> GroupOpts = proplists:get_value(Group, GroupsOpts, []), proplists:get_value(displayed_groups, GroupOpts, []). -broadcast_displayed_to_user(LUser, LServer, Host, Subscription, DisplayedGroups) -> - [broadcast_members_to_user(LUser, LServer, DGroup, Host, - Subscription) - || DGroup <- DisplayedGroups]. - push_displayed_to_user(LUser, LServer, Host, Subscription, DisplayedGroups) -> [push_members_to_user(LUser, LServer, DGroup, Host, Subscription) @@ -612,7 +586,7 @@ remove_user_from_group(Host, US, Group) -> {LUser, LServer} = US, case ejabberd_regexp:run(LUser, <<"^@.+@\$">>) of match -> - GroupOpts = (?MODULE):get_group_opts(Host, Group), + GroupOpts = mod_shared_roster:get_group_opts(Host, Group), NewGroupOpts = case LUser of <<"@all@">> -> lists:filter(fun (X) -> X /= {all_users, true} @@ -623,7 +597,7 @@ remove_user_from_group(Host, US, Group) -> end, GroupOpts) end, - (?MODULE):set_group_opts(Host, Group, NewGroupOpts); + mod_shared_roster:set_group_opts(Host, Group, NewGroupOpts); nomatch -> Mod = gen_mod:db_mod(Host, ?MODULE), Result = Mod:remove_user_from_group(Host, US, Group), @@ -646,19 +620,15 @@ push_members_to_user(LUser, LServer, Group, Host, end, Members). -broadcast_members_to_user(LUser, LServer, Group, Host, Subscription) -> - Members = get_group_users(Host, Group), - lists:foreach( - fun({U, S}) -> - broadcast_subscription(U, S, {LUser, LServer, <<"">>}, Subscription) - end, Members). - +-spec register_user(binary(), binary()) -> ok. register_user(User, Server) -> Groups = get_user_groups({User, Server}), [push_user_to_displayed(User, Server, Group, Server, both, displayed_to_groups(Group, Server)) - || Group <- Groups]. + || Group <- Groups], + ok. +-spec remove_user(binary(), binary()) -> ok. remove_user(User, Server) -> push_user_to_members(User, Server, remove). @@ -696,28 +666,22 @@ push_user_to_displayed(LUser, LServer, Group, Host, Subscription, DisplayedToGro GroupName, Subscription) || GroupD <- DisplayedToGroupsOpts]. -broadcast_user_to_displayed(LUser, LServer, Host, Subscription, DisplayedToGroupsOpts) -> - [broadcast_user_to_group(LUser, LServer, GroupD, Host, Subscription) - || GroupD <- DisplayedToGroupsOpts]. - push_user_to_group(LUser, LServer, Group, Host, GroupName, Subscription) -> lists:foreach(fun ({U, S}) when (U == LUser) and (S == LServer) -> ok; ({U, S}) -> - push_roster_item(U, S, LUser, LServer, GroupName, - Subscription) + case lists:member(S, ejabberd_option:hosts()) of + true -> + push_roster_item(U, S, LUser, LServer, GroupName, + Subscription); + _ -> + ok + end end, get_group_users(Host, Group)). -broadcast_user_to_group(LUser, LServer, Group, Host, Subscription) -> - lists:foreach( - fun({U, S}) when (U == LUser) and (S == LServer) -> ok; - ({U, S}) -> - broadcast_subscription(LUser, LServer, {U, S, <<"">>}, Subscription) - end, get_group_users(Host, Group)). - %% Get list of groups to which this group is displayed displayed_to_groups(GroupName, LServer) -> GroupsOpts = groups_with_opts(LServer), @@ -730,18 +694,9 @@ displayed_to_groups(GroupName, LServer) -> [Name || {Name, _} <- Gs]. push_item(User, Server, Item) -> - Stanza = jlib:iq_to_xml(#iq{type = set, - xmlns = ?NS_ROSTER, - id = <<"push", (randoms:get_string())/binary>>, - sub_el = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_ROSTER}], - children = [item_to_xml(Item)]}]}), - lists:foreach(fun (Resource) -> - JID = jid:make(User, Server, Resource), - ejabberd_router:route(jid:remove_resource(JID), JID, Stanza) - end, - ejabberd_sm:get_user_resources(User, Server)). + mod_roster:push_item(jid:make(User, Server), + Item#roster{subscription = none}, + Item). push_roster_item(User, Server, ContactU, ContactS, GroupName, Subscription) -> @@ -752,65 +707,16 @@ push_roster_item(User, Server, ContactU, ContactS, groups = [GroupName]}, push_item(User, Server, Item). -item_to_xml(Item) -> - Attrs1 = [{<<"jid">>, - jid:to_string(Item#roster.jid)}], - Attrs2 = case Item#roster.name of - <<"">> -> Attrs1; - Name -> [{<<"name">>, Name} | Attrs1] - end, - Attrs3 = case Item#roster.subscription of - none -> [{<<"subscription">>, <<"none">>} | Attrs2]; - from -> [{<<"subscription">>, <<"from">>} | Attrs2]; - to -> [{<<"subscription">>, <<"to">>} | Attrs2]; - both -> [{<<"subscription">>, <<"both">>} | Attrs2]; - remove -> [{<<"subscription">>, <<"remove">>} | Attrs2] - end, - Attrs4 = case ask_to_pending(Item#roster.ask) of - out -> [{<<"ask">>, <<"subscribe">>} | Attrs3]; - both -> [{<<"ask">>, <<"subscribe">>} | Attrs3]; - _ -> Attrs3 - end, - SubEls1 = lists:map(fun (G) -> - #xmlel{name = <<"group">>, attrs = [], - children = [{xmlcdata, G}]} - end, - Item#roster.groups), - SubEls = SubEls1 ++ Item#roster.xs, - #xmlel{name = <<"item">>, attrs = Attrs4, - children = SubEls}. - -ask_to_pending(subscribe) -> out; -ask_to_pending(unsubscribe) -> none; -ask_to_pending(Ask) -> Ask. - -user_available(New) -> - LUser = New#jid.luser, - LServer = New#jid.lserver, - 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 -> - UserGroups = get_user_groups({LUser, LServer}), - lists:foreach(fun (OG) -> - ?DEBUG("user_available: pushing ~p @ ~p grp ~p", - [LUser, LServer, OG]), - DisplayedToGroups = displayed_to_groups(OG, LServer), - DisplayedGroups = get_displayed_groups(OG, LServer), - broadcast_displayed_to_user(LUser, LServer, LServer, both, DisplayedGroups), - broadcast_user_to_displayed(LUser, LServer, LServer, both, DisplayedToGroups) - end, - UserGroups); - _ -> ok - end. +-spec c2s_self_presence({presence(), ejabberd_c2s:state()}) + -> {presence(), ejabberd_c2s:state()}. +c2s_self_presence(Acc) -> + Acc. +-spec unset_presence(binary(), binary(), binary(), binary()) -> ok. unset_presence(LUser, LServer, Resource, Status) -> Resources = ejabberd_sm:get_user_resources(LUser, LServer), - ?DEBUG("unset_presence for ~p @ ~p / ~p -> ~p " + ?DEBUG("Unset_presence for ~p @ ~p / ~p -> ~p " "(~p resources)", [LUser, LServer, Resource, Status, length(Resources)]), case length(Resources) of @@ -831,7 +737,7 @@ unset_presence(LUser, LServer, Resource, Status) -> %%--------------------- webadmin_menu(Acc, _Host, Lang) -> - [{<<"shared-roster">>, ?T(<<"Shared Roster Groups">>)} + [{<<"shared-roster">>, translate:translate(Lang, ?T("Shared Roster Groups"))} | Acc]. webadmin_page(_, Host, @@ -850,7 +756,7 @@ webadmin_page(Acc, _, _) -> Acc. list_shared_roster_groups(Host, Query, Lang) -> Res = list_sr_groups_parse_query(Host, Query), - SRGroups = (?MODULE):list_groups(Host), + SRGroups = mod_shared_roster:list_groups(Host), FGroups = (?XAE(<<"table">>, [], [?XE(<<"tbody">>, (lists:map(fun (Group) -> @@ -872,13 +778,13 @@ list_shared_roster_groups(Host, Query, Lang) -> <<"">>)]), ?XE(<<"td">>, [?INPUTT(<<"submit">>, <<"addnew">>, - <<"Add New">>)])])]))])), - (?H1GL((?T(<<"Shared Roster Groups">>)), - <<"mod_shared_roster">>, <<"mod_shared_roster">>)) + ?T("Add New"))])])]))])), + (?H1GL((translate:translate(Lang, ?T("Shared Roster Groups"))), + <<"mod-shared-roster">>, <<"mod_shared_roster">>)) ++ case Res of - ok -> [?XREST(<<"Submitted">>)]; - error -> [?XREST(<<"Bad format">>)]; + ok -> [?XREST(?T("Submitted"))]; + error -> [?XREST(?T("Bad format"))]; nothing -> [] end ++ @@ -886,7 +792,7 @@ list_shared_roster_groups(Host, Query, Lang) -> [{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}], [FGroups, ?BR, ?INPUTT(<<"submit">>, <<"delete">>, - <<"Delete Selected">>)])]. + ?T("Delete Selected"))])]. list_sr_groups_parse_query(Host, Query) -> case lists:keysearch(<<"addnew">>, 1, Query) of @@ -901,15 +807,15 @@ list_sr_groups_parse_query(Host, Query) -> list_sr_groups_parse_addnew(Host, Query) -> case lists:keysearch(<<"namenew">>, 1, Query) of {value, {_, Group}} when Group /= <<"">> -> - (?MODULE):create_group(Host, Group), ok; + mod_shared_roster:create_group(Host, Group), ok; _ -> error end. list_sr_groups_parse_delete(Host, Query) -> - SRGroups = (?MODULE):list_groups(Host), + SRGroups = mod_shared_roster:list_groups(Host), lists:foreach(fun (Group) -> case lists:member({<<"selected">>, Group}, Query) of - true -> (?MODULE):delete_group(Host, Group); + true -> mod_shared_roster:delete_group(Host, Group); _ -> ok end end, @@ -919,14 +825,14 @@ list_sr_groups_parse_delete(Host, Query) -> shared_roster_group(Host, Group, Query, Lang) -> Res = shared_roster_group_parse_query(Host, Group, Query), - GroupOpts = (?MODULE):get_group_opts(Host, Group), + GroupOpts = mod_shared_roster:get_group_opts(Host, Group), Name = get_opt(GroupOpts, name, <<"">>), Description = get_opt(GroupOpts, description, <<"">>), AllUsers = get_opt(GroupOpts, all_users, false), OnlineUsers = get_opt(GroupOpts, online_users, false), DisplayedGroups = get_opt(GroupOpts, displayed_groups, []), - Members = (?MODULE):get_group_explicit_users(Host, + Members = mod_shared_roster:get_group_explicit_users(Host, Group), FMembers = iolist_to_binary( [if AllUsers -> <<"@all@\n">>; @@ -943,44 +849,50 @@ shared_roster_group(Host, Group, Query, Lang) -> [{<<"class">>, <<"withtextareas">>}], [?XE(<<"tbody">>, [?XE(<<"tr">>, - [?XCT(<<"td">>, <<"Name:">>), + [?XCT(<<"td">>, ?T("Name:")), ?XE(<<"td">>, [?INPUT(<<"text">>, <<"name">>, Name)])]), ?XE(<<"tr">>, - [?XCT(<<"td">>, <<"Description:">>), + [?XCT(<<"td">>, ?T("Description:")), ?XE(<<"td">>, [?TEXTAREA(<<"description">>, - jlib:integer_to_binary(lists:max([3, + integer_to_binary(lists:max([3, DescNL])), <<"20">>, Description)])]), ?XE(<<"tr">>, - [?XCT(<<"td">>, <<"Members:">>), + [?XCT(<<"td">>, ?T("Members:")), ?XE(<<"td">>, [?TEXTAREA(<<"members">>, - jlib:integer_to_binary(lists:max([3, - byte_size(FMembers)])), + integer_to_binary(lists:max([3, + length(Members)+3])), <<"20">>, FMembers)])]), ?XE(<<"tr">>, - [?XCT(<<"td">>, <<"Displayed Groups:">>), + [?XCT(<<"td">>, ?T("Displayed Groups:")), ?XE(<<"td">>, [?TEXTAREA(<<"dispgroups">>, - jlib:integer_to_binary(lists:max([3, length(FDisplayedGroups)])), + integer_to_binary(lists:max([3, length(FDisplayedGroups)])), <<"20">>, list_to_binary(FDisplayedGroups))])])])])), - (?H1GL((?T(<<"Shared Roster Groups">>)), - <<"mod_shared_roster">>, <<"mod_shared_roster">>)) + (?H1GL((translate:translate(Lang, ?T("Shared Roster Groups"))), + <<"mod-shared-roster">>, <<"mod_shared_roster">>)) ++ - [?XC(<<"h2">>, <<(?T(<<"Group ">>))/binary, Group/binary>>)] ++ + [?XC(<<"h2">>, <<(translate:translate(Lang, ?T("Group ")))/binary, Group/binary>>)] ++ case Res of - ok -> [?XREST(<<"Submitted">>)]; - error -> [?XREST(<<"Bad format">>)]; + ok -> [?XREST(?T("Submitted"))]; + {error_jids, NonAddedList1} -> + NonAddedList2 = [jid:encode({U,S,<<>>}) || {U,S} <- NonAddedList1], + NonAddedList3 = str:join(NonAddedList2, <<", ">>), + NonAddedText1 = translate:translate(Lang, ?T("Members not added (inexistent vhost): ")), + NonAddedText2 = str:concat(NonAddedText1, NonAddedList3), + [?XRES(NonAddedText2)]; + error -> [?XREST(?T("Bad format"))]; nothing -> [] end ++ [?XAE(<<"form">>, [{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}], [FGroup, ?BR, - ?INPUTT(<<"submit">>, <<"submit">>, <<"Submit">>)])]. + ?INPUTT(<<"submit">>, <<"submit">>, ?T("Submit"))])]. shared_roster_group_parse_query(Host, Group, Query) -> case lists:keysearch(<<"submit">>, 1, Query) of @@ -1003,7 +915,7 @@ shared_roster_group_parse_query(Host, Group, Query) -> DispGroupsOpt = if DispGroups == [] -> []; true -> [{displayed_groups, DispGroups}] end, - OldMembers = (?MODULE):get_group_explicit_users(Host, + OldMembers = mod_shared_roster:get_group_explicit_users(Host, Group), SJIDs = str:tokens(SMembers, <<", \r\n">>), NewMembers = lists:foldl(fun (_SJID, error) -> error; @@ -1012,15 +924,13 @@ shared_roster_group_parse_query(Host, Group, Query) -> <<"@all@">> -> USs; <<"@online@">> -> USs; _ -> - case jid:from_string(SJID) - of - JID - when is_record(JID, - jid) -> + try jid:decode(SJID) of + JID -> [{JID#jid.luser, JID#jid.lserver} - | USs]; - error -> error + | USs] + catch _:{bad_jid, _} -> + error end end end, @@ -1040,7 +950,7 @@ shared_roster_group_parse_query(Host, Group, Query) -> RemovedDisplayedGroups = CurrentDisplayedGroups -- DispGroups, displayed_groups_update(OldMembers, RemovedDisplayedGroups, remove), displayed_groups_update(OldMembers, AddedDisplayedGroups, both), - (?MODULE):set_group_opts(Host, Group, + mod_shared_roster:set_group_opts(Host, Group, NameOpt ++ DispGroupsOpt ++ DescriptionOpt ++ @@ -1050,17 +960,20 @@ shared_roster_group_parse_query(Host, Group, Query) -> AddedMembers = NewMembers -- OldMembers, RemovedMembers = OldMembers -- NewMembers, lists:foreach(fun (US) -> - (?MODULE):remove_user_from_group(Host, + mod_shared_roster:remove_user_from_group(Host, US, Group) end, RemovedMembers), - lists:foreach(fun (US) -> - (?MODULE):add_user_to_group(Host, US, + NonAddedMembers = lists:filter(fun (US) -> + error == mod_shared_roster:add_user_to_group(Host, US, Group) end, AddedMembers), - ok + case NonAddedMembers of + [] -> ok; + _ -> {error_jids, NonAddedMembers} + end end; _ -> nothing end. @@ -1072,7 +985,7 @@ get_opt(Opts, Opt, Default) -> end. us_to_list({User, Server}) -> - jid:to_string({User, Server, <<"">>}). + jid:encode({User, Server, <<"">>}). split_grouphost(Host, Group) -> case str:tokens(Group, <<"@">>) of @@ -1080,24 +993,11 @@ split_grouphost(Host, Group) -> [_] -> {Host, Group} end. -broadcast_subscription(User, Server, ContactJid, Subscription) -> - ejabberd_sm:route( - jid:make(<<"">>, Server, <<"">>), - jid:make(User, Server, <<"">>), - {broadcast, {item, ContactJid, - Subscription}}). - displayed_groups_update(Members, DisplayedGroups, Subscription) -> - lists:foreach(fun({U, S}) -> - push_displayed_to_user(U, S, S, Subscription, DisplayedGroups), - case Subscription of - both -> - broadcast_displayed_to_user(U, S, S, to, DisplayedGroups), - broadcast_displayed_to_user(U, S, S, from, DisplayedGroups); - Subscr -> - broadcast_displayed_to_user(U, S, S, Subscr, DisplayedGroups) - end - end, Members). + lists:foreach( + fun({U, S}) -> + push_displayed_to_user(U, S, S, Subscription, DisplayedGroups) + end, Members). opts_to_binary(Opts) -> lists:map( @@ -1115,13 +1015,19 @@ export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). -import(LServer) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:import(LServer). +import_info() -> + [{<<"sr_group">>, 3}, {<<"sr_user">>, 3}]. -import(LServer, DBType, Data) -> +import_start(LServer, DBType) -> Mod = gen_mod:db_mod(DBType, ?MODULE), - Mod:import(LServer, Data). + Mod:init(LServer, []). + +import(LServer, {sql, _}, DBType, Tab, L) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(LServer, Tab, L). + +mod_opt_type(db_type) -> + econf:db_type(?MODULE). -mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; -mod_opt_type(_) -> [db_type]. +mod_options(Host) -> + [{db_type, ejabberd_config:default_db(Host, ?MODULE)}]. |