diff options
Diffstat (limited to 'src/mod_shared_roster.erl')
-rw-r--r-- | src/mod_shared_roster.erl | 1836 |
1 files changed, 942 insertions, 894 deletions
diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 567c7ea57..057deba20 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -25,190 +25,189 @@ %%%---------------------------------------------------------------------- -module(mod_shared_roster). + -author('alexey@process-one.net'). -behaviour(gen_mod). --export([start/2, stop/1, - item_to_xml/1, - webadmin_menu/3, webadmin_page/3, - get_user_roster/2, - get_subscription_lists/3, - get_jid_info/4, - process_item/2, - in_subscription/6, - out_subscription/4, - user_available/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, - remove_user_from_group/3]). +-export([start/2, stop/1, item_to_xml/1, export/1, + webadmin_menu/3, webadmin_page/3, get_user_roster/2, + get_subscription_lists/3, get_jid_info/4, + process_item/2, in_subscription/6, out_subscription/4, + user_available/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, remove_user_from_group/3]). -include("ejabberd.hrl"). + -include("jlib.hrl"). + -include("mod_roster.hrl"). + -include("web/ejabberd_http.hrl"). + -include("web/ejabberd_web_admin.hrl"). --record(sr_group, {group_host, opts}). --record(sr_user, {us, group_host}). +-record(sr_group, {group_host = {<<"">>, <<"">>} :: {'$1' | binary(), '$2' | binary()}, + opts = [] :: list() | '_' | '$2'}). + +-record(sr_user, {us = {<<"">>, <<"">>} :: {binary(), binary()}, + group_host = {<<"">>, <<"">>} :: {binary(), binary()}}). start(Host, Opts) -> case gen_mod:db_type(Opts) of - mnesia -> - 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); - _ -> - ok + mnesia -> + 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)}]), + update_tables(), + mnesia:add_table_index(sr_user, group_host); + _ -> ok end, - ejabberd_hooks:add(webadmin_menu_host, Host, - ?MODULE, webadmin_menu, 70), - ejabberd_hooks:add(webadmin_page_host, Host, - ?MODULE, webadmin_page, 50), - ejabberd_hooks:add(roster_get, Host, - ?MODULE, get_user_roster, 70), + ejabberd_hooks:add(webadmin_menu_host, Host, ?MODULE, + webadmin_menu, 70), + ejabberd_hooks:add(webadmin_page_host, Host, ?MODULE, + webadmin_page, 50), + ejabberd_hooks:add(roster_get, Host, ?MODULE, + get_user_roster, 70), ejabberd_hooks:add(roster_in_subscription, Host, - ?MODULE, in_subscription, 30), + ?MODULE, in_subscription, 30), ejabberd_hooks:add(roster_out_subscription, Host, - ?MODULE, out_subscription, 30), + ?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(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). + 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(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). + %%ejabberd_hooks:add(remove_user, Host, %% ?MODULE, remove_user, 50), stop(Host) -> - ejabberd_hooks:delete(webadmin_menu_host, Host, - ?MODULE, webadmin_menu, 70), - ejabberd_hooks:delete(webadmin_page_host, Host, - ?MODULE, webadmin_page, 50), - ejabberd_hooks:delete(roster_get, Host, - ?MODULE, get_user_roster, 70), + ejabberd_hooks:delete(webadmin_menu_host, Host, ?MODULE, + webadmin_menu, 70), + ejabberd_hooks:delete(webadmin_page_host, Host, ?MODULE, + webadmin_page, 50), + ejabberd_hooks:delete(roster_get, Host, ?MODULE, + get_user_roster, 70), ejabberd_hooks:delete(roster_in_subscription, Host, - ?MODULE, in_subscription, 30), + ?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), + ?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), + ?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(unset_presence_hook, Host, ?MODULE, unset_presence, 50), - ejabberd_hooks:delete(register_user, Host, - ?MODULE, register_user, 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), - + ejabberd_hooks:delete(remove_user, Host, ?MODULE, + remove_user, + 50).%%ejabberd_hooks:delete(remove_user, Host, + %% ?MODULE, remove_user, 50), get_user_roster(Items, US) -> {U, S} = US, DisplayedGroups = get_user_displayed_groups(US), - %% Get shared roster users in all groups and remove self: - SRUsers = - lists:foldl( - fun(Group, Acc1) -> - GroupName = get_group_name(S, Group), - lists:foldl( - fun(User, Acc2) -> - if User == US -> Acc2; - true -> dict:append(User, - GroupName, - Acc2) - end - end, Acc1, get_group_users(S, Group)) - end, dict:new(), DisplayedGroups), - - %% If partially subscribed users are also in shared roster, show them as - %% totally subscribed: - {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), - - %% Export items in roster format: + SRUsers = lists:foldl(fun (Group, Acc1) -> + GroupName = get_group_name(S, Group), + lists:foldl(fun (User, Acc2) -> + if User == US -> Acc2; + true -> + dict:append(User, + GroupName, + Acc2) + end + 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), ModVcard = get_vcard_module(S), - SRItems = [#roster{usj = {U, S, {U1, S1, ""}}, - us = US, - jid = {U1, S1, ""}, + SRItems = [#roster{usj = {U, S, {U1, S1, <<"">>}}, + us = US, jid = {U1, S1, <<"">>}, name = get_rosteritem_name(ModVcard, U1, S1), - subscription = both, - ask = none, - groups = GroupNames} || - {{U1, S1}, GroupNames} <- dict:to_list(SRUsersRest)], + 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)]. + [M + || M <- Modules, + (M == mod_vcard) or (M == mod_vcard_ldap)]. -get_rosteritem_name([], _, _) -> - ""; +get_rosteritem_name([], _, _) -> <<"">>; get_rosteritem_name([ModVcard], U, S) -> - From = jlib:make_jid("", S, ?MODULE), - To = jlib:make_jid(U, S, ""), - IQ = {iq,"",get,"vcard-temp","", - {xmlelement,"vCard",[{"xmlns","vcard-temp"}],[]}}, + From = jlib:make_jid(<<"">>, S, jlib:atom_to_binary(?MODULE)), + To = jlib:make_jid(U, S, <<"">>), + IQ = {iq, <<"">>, get, <<"vcard-temp">>, <<"">>, + #xmlel{name = <<"vCard">>, + attrs = [{<<"xmlns">>, <<"vcard-temp">>}], + children = []}}, IQ_Vcard = ModVcard:process_sm_iq(From, To, IQ), - try get_rosteritem_name_vcard(IQ_Vcard#iq.sub_el) - catch E1:E2 -> - ?ERROR_MSG("Error ~p found when trying to get the vCard of ~s@~s " - "in ~p:~n ~p", [E1, U, S, ModVcard, E2]), - "" + try get_rosteritem_name_vcard(IQ_Vcard#iq.sub_el) catch + E1:E2 -> + ?ERROR_MSG("Error ~p found when trying to get the " + "vCard of ~s@~s in ~p:~n ~p", + [E1, U, S, ModVcard, E2]), + <<"">> end. -get_rosteritem_name_vcard([]) -> - ""; +get_rosteritem_name_vcard([]) -> <<"">>; get_rosteritem_name_vcard([Vcard]) -> - case xml:get_path_s(Vcard, [{elem, "NICKNAME"}, cdata]) of - "" -> xml:get_path_s(Vcard, [{elem, "FN"}, cdata]); - Nickname -> Nickname + case xml:get_path_s(Vcard, + [{elem, <<"NICKNAME">>}, cdata]) + of + <<"">> -> + xml:get_path_s(Vcard, [{elem, <<"FN">>}, cdata]); + Nickname -> Nickname end. %% This function rewrites the roster entries when moving or renaming @@ -219,423 +218,390 @@ process_item(RosterItem, Host) -> NameTo = RosterItem#roster.name, USTo = {UserTo, ServerTo}, DisplayedGroups = get_user_displayed_groups(USFrom), - CommonGroups = lists:filter(fun(Group) -> + CommonGroups = lists:filter(fun (Group) -> is_user_in_group(USTo, Group, Host) - end, DisplayedGroups), + end, + DisplayedGroups), case CommonGroups of - [] -> RosterItem; - %% Roster item cannot be removed: We simply reset the original groups: - _ when RosterItem#roster.subscription == remove -> - GroupNames = lists:map(fun(Group) -> - get_group_name(Host, Group) - end, CommonGroups), - RosterItem#roster{subscription = both, ask = none, - groups=[GroupNames]}; - %% Both users have at least a common shared group, - %% So each user can see the other - _ -> - %% Check if the list of groups of the new roster item - %% include at least a new one - case lists:subtract(RosterItem#roster.groups, CommonGroups) of - %% If it doesn't, then remove this user from any - %% existing roster groups. - [] -> - %% Remove pending subscription by setting it - %% unsubscribed. - - %% Remove pending out subscription - mod_roster:out_subscription(UserTo, ServerTo, - jlib:make_jid(UserFrom, ServerFrom, ""), - unsubscribe), - - %% Remove pending in subscription - mod_roster:in_subscription(aaaa, UserFrom, ServerFrom, - jlib:make_jid(UserTo, ServerTo, ""), - unsubscribe, ""), - - %% But we're still subscribed, so respond as such. - RosterItem#roster{subscription = both, ask = none}; - %% If so, it means the user wants to add that contact - %% to his personal roster - PersonalGroups -> - %% Store roster items in From and To rosters - set_new_rosteritems(UserFrom, ServerFrom, - UserTo, ServerTo, ResourceTo, NameTo, - PersonalGroups) - end + [] -> RosterItem; + %% Roster item cannot be removed: We simply reset the original groups: + _ when RosterItem#roster.subscription == remove -> + GroupNames = lists:map(fun (Group) -> + get_group_name(Host, Group) + end, + CommonGroups), + RosterItem#roster{subscription = both, ask = none, + groups = GroupNames}; + %% Both users have at least a common shared group, + %% So each user can see the other + _ -> + case lists:subtract(RosterItem#roster.groups, + CommonGroups) + of + %% If it doesn't, then remove this user from any + %% existing roster groups. + [] -> + mod_roster:out_subscription(UserTo, ServerTo, + jlib:make_jid(UserFrom, ServerFrom, + <<"">>), + unsubscribe), + mod_roster:in_subscription(aaaa, UserFrom, ServerFrom, + jlib:make_jid(UserTo, ServerTo, + <<"">>), + unsubscribe, <<"">>), + RosterItem#roster{subscription = both, ask = none}; + %% If so, it means the user wants to add that contact + %% to his personal roster + PersonalGroups -> + set_new_rosteritems(UserFrom, ServerFrom, UserTo, + ServerTo, ResourceTo, NameTo, + PersonalGroups) + end end. -build_roster_record(User1, Server1, User2, Server2, Name2, Groups) -> - USR2 = {User2, Server2, ""}, +build_roster_record(User1, Server1, User2, Server2, + Name2, Groups) -> + USR2 = {User2, Server2, <<"">>}, #roster{usj = {User1, Server1, USR2}, - us = {User1, Server1}, - jid = USR2, - name = Name2, - subscription = both, - ask = none, - groups = Groups - }. - -set_new_rosteritems(UserFrom, ServerFrom, - UserTo, ServerTo, ResourceTo, NameTo, GroupsFrom) -> + us = {User1, Server1}, jid = USR2, name = Name2, + subscription = both, ask = none, groups = Groups}. + +set_new_rosteritems(UserFrom, ServerFrom, UserTo, + ServerTo, ResourceTo, NameTo, GroupsFrom) -> RIFrom = build_roster_record(UserFrom, ServerFrom, UserTo, ServerTo, NameTo, GroupsFrom), set_item(UserFrom, ServerFrom, ResourceTo, RIFrom), - JIDTo = jlib:make_jid(UserTo, ServerTo, ""), - - JIDFrom = jlib:make_jid(UserFrom, ServerFrom, ""), - RITo = build_roster_record(UserTo, ServerTo, - UserFrom, ServerFrom, UserFrom,[]), - set_item(UserTo, ServerTo, "", RITo), - - %% From requests - mod_roster:out_subscription(UserFrom, ServerFrom, JIDTo, subscribe), - mod_roster:in_subscription(aaa, UserTo, ServerTo, JIDFrom, subscribe, ""), - - %% To accepts - mod_roster:out_subscription(UserTo, ServerTo, JIDFrom, subscribed), - mod_roster:in_subscription(aaa, UserFrom, ServerFrom, JIDTo, subscribed, ""), - - %% To requests - mod_roster:out_subscription(UserTo, ServerTo, JIDFrom, subscribe), - mod_roster:in_subscription(aaa, UserFrom, ServerFrom, JIDTo, subscribe, ""), - - %% From accepts - mod_roster:out_subscription(UserFrom, ServerFrom, JIDTo, subscribed), - mod_roster:in_subscription(aaa, UserTo, ServerTo, JIDFrom, subscribed, ""), - + JIDTo = jlib:make_jid(UserTo, ServerTo, <<"">>), + JIDFrom = jlib:make_jid(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, <<"">>), RIFrom. set_item(User, Server, Resource, Item) -> ResIQ = #iq{type = set, xmlns = ?NS_ROSTER, - id = "push" ++ randoms:get_string(), - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_ROSTER}], - [mod_roster:item_to_xml(Item)]}]}, - ejabberd_router:route( - jlib:make_jid(User, Server, Resource), - jlib:make_jid("", Server, ""), - jlib:iq_to_xml(ResIQ)). - + 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(jlib:make_jid(User, Server, + Resource), + jlib:make_jid(<<"">>, Server, <<"">>), + jlib:iq_to_xml(ResIQ)). 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], + 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) -> +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), + 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} + {ok, GroupNames} -> + NewGroups = if Groups == [] -> GroupNames; + true -> Groups + end, + {both, NewGroups}; + error -> {Subscription, Groups} end. -in_subscription(Acc, User, Server, JID, Type, _Reason) -> +in_subscription(Acc, User, Server, JID, Type, + _Reason) -> process_subscription(in, User, Server, JID, Type, Acc). -out_subscription(UserFrom, ServerFrom, JIDTo, unsubscribed) -> - %% Remove pending out subscription +out_subscription(UserFrom, ServerFrom, JIDTo, + unsubscribed) -> #jid{luser = UserTo, lserver = ServerTo} = JIDTo, - JIDFrom = jlib:make_jid(UserFrom, UserTo, ""), - mod_roster:out_subscription(UserTo, ServerTo, JIDFrom, unsubscribe), - - %% Remove pending in subscription - mod_roster:in_subscription(aaaa, UserFrom, ServerFrom, JIDTo, unsubscribe, ""), - - process_subscription(out, UserFrom, ServerFrom, JIDTo, unsubscribed, false); + JIDFrom = jlib:make_jid(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). + process_subscription(out, User, Server, JID, Type, + false). -process_subscription(Direction, User, Server, JID, _Type, Acc) -> +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)), + {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)), + 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 + true -> + case Direction of + in -> {stop, false}; + out -> stop + end; + false -> Acc end. list_groups(Host) -> list_groups(Host, gen_mod:db_type(Host, ?MODULE)). list_groups(Host, mnesia) -> - mnesia:dirty_select( - sr_group, - [{#sr_group{group_host = {'$1', '$2'}, - _ = '_'}, - [{'==', '$2', Host}], - ['$1']}]); + mnesia:dirty_select(sr_group, + [{#sr_group{group_host = {'$1', '$2'}, _ = '_'}, + [{'==', '$2', Host}], ['$1']}]); list_groups(Host, odbc) -> - case ejabberd_odbc:sql_query( - Host, ["select name from sr_group;"]) of - {selected, ["name"], Rs} -> - [G || {G} <- Rs]; - _ -> - [] + case ejabberd_odbc:sql_query(Host, + [<<"select name from sr_group;">>]) + of + {selected, [<<"name">>], Rs} -> [G || [G] <- Rs]; + _ -> [] end. groups_with_opts(Host) -> groups_with_opts(Host, gen_mod:db_type(Host, ?MODULE)). groups_with_opts(Host, mnesia) -> - Gs = mnesia:dirty_select( - sr_group, - [{#sr_group{group_host={'$1', Host}, opts='$2', _='_'}, - [], - [['$1','$2']] }]), - lists:map(fun([G,O]) -> {G, O} end, Gs); + Gs = mnesia:dirty_select(sr_group, + [{#sr_group{group_host = {'$1', Host}, opts = '$2', + _ = '_'}, + [], [['$1', '$2']]}]), + lists:map(fun ([G, O]) -> {G, O} end, Gs); groups_with_opts(Host, odbc) -> - case ejabberd_odbc:sql_query( - Host, ["select name, opts from sr_group;"]) of - {selected, ["name", "opts"], Rs} -> - [{G, ejabberd_odbc:decode_term(Opts)} || {G, Opts} <- Rs]; - _ -> - [] + case ejabberd_odbc:sql_query(Host, + [<<"select name, opts from sr_group;">>]) + of + {selected, [<<"name">>, <<"opts">>], Rs} -> + [{G, opts_to_binary(ejabberd_odbc:decode_term(Opts))} + || [G, Opts] <- Rs]; + _ -> [] end. create_group(Host, Group) -> create_group(Host, Group, []). create_group(Host, Group, Opts) -> - create_group(Host, Group, Opts, gen_mod:db_type(Host, ?MODULE)). + create_group(Host, Group, Opts, + gen_mod:db_type(Host, ?MODULE)). create_group(Host, Group, Opts, mnesia) -> R = #sr_group{group_host = {Group, Host}, opts = Opts}, - F = fun() -> - mnesia:write(R) - end, + F = fun () -> mnesia:write(R) end, mnesia:transaction(F); create_group(Host, Group, Opts, odbc) -> SGroup = ejabberd_odbc:escape(Group), SOpts = ejabberd_odbc:encode_term(Opts), - F = fun() -> - odbc_queries:update_t("sr_group", - ["name", "opts"], - [SGroup, SOpts], - ["name='", SGroup, "'"]) - end, + F = fun () -> + odbc_queries:update_t(<<"sr_group">>, + [<<"name">>, <<"opts">>], [SGroup, SOpts], + [<<"name='">>, SGroup, <<"'">>]) + end, ejabberd_odbc:sql_transaction(Host, F). delete_group(Host, Group) -> - delete_group(Host, Group, gen_mod:db_type(Host, ?MODULE)). + delete_group(Host, Group, + gen_mod:db_type(Host, ?MODULE)). delete_group(Host, Group, mnesia) -> GroupHost = {Group, Host}, - F = fun() -> - %% Delete the group ... + F = fun () -> mnesia:delete({sr_group, GroupHost}), - %% ... and its users - Users = mnesia:index_read(sr_user, GroupHost, #sr_user.group_host), - lists:foreach(fun(UserEntry) -> + Users = mnesia:index_read(sr_user, GroupHost, + #sr_user.group_host), + lists:foreach(fun (UserEntry) -> mnesia:delete_object(UserEntry) - end, Users) + end, + Users) end, mnesia:transaction(F); delete_group(Host, Group, odbc) -> SGroup = ejabberd_odbc:escape(Group), - F = fun() -> - ejabberd_odbc:sql_query_t( - ["delete from sr_group where name='", SGroup, "';"]), - ejabberd_odbc:sql_query_t( - ["delete from sr_user where grp='", SGroup, "';"]) - end, + F = fun () -> + ejabberd_odbc:sql_query_t([<<"delete from sr_group where name='">>, + SGroup, <<"';">>]), + ejabberd_odbc:sql_query_t([<<"delete from sr_user where grp='">>, + SGroup, <<"';">>]) + end, ejabberd_odbc:sql_transaction(Host, F). get_group_opts(Host, Group) -> - get_group_opts(Host, Group, gen_mod:db_type(Host, ?MODULE)). + get_group_opts(Host, Group, + gen_mod:db_type(Host, ?MODULE)). get_group_opts(Host, Group, mnesia) -> case catch mnesia:dirty_read(sr_group, {Group, Host}) of - [#sr_group{opts = Opts}] -> - Opts; - _ -> - error + [#sr_group{opts = Opts}] -> Opts; + _ -> error end; get_group_opts(Host, Group, odbc) -> SGroup = ejabberd_odbc:escape(Group), - case catch ejabberd_odbc:sql_query( - Host, ["select opts from sr_group " - "where name='", SGroup, "';"]) of - {selected, ["opts"], [{SOpts}]} -> - ejabberd_odbc:decode_term(SOpts); - _ -> - error + case catch ejabberd_odbc:sql_query(Host, + [<<"select opts from sr_group where name='">>, + SGroup, <<"';">>]) + of + {selected, [<<"opts">>], [[SOpts]]} -> + opts_to_binary(ejabberd_odbc:decode_term(SOpts)); + _ -> error end. set_group_opts(Host, Group, Opts) -> - set_group_opts(Host, Group, Opts, gen_mod:db_type(Host, ?MODULE)). + set_group_opts(Host, Group, Opts, + gen_mod:db_type(Host, ?MODULE)). set_group_opts(Host, Group, Opts, mnesia) -> R = #sr_group{group_host = {Group, Host}, opts = Opts}, - F = fun() -> - mnesia:write(R) - end, + F = fun () -> mnesia:write(R) end, mnesia:transaction(F); set_group_opts(Host, Group, Opts, odbc) -> SGroup = ejabberd_odbc:escape(Group), SOpts = ejabberd_odbc:encode_term(Opts), - F = fun() -> - odbc_queries:update_t("sr_group", - ["name", "opts"], - [SGroup, SOpts], - ["name='", SGroup, "'"]) - end, + F = fun () -> + odbc_queries:update_t(<<"sr_group">>, + [<<"name">>, <<"opts">>], [SGroup, SOpts], + [<<"name='">>, SGroup, <<"'">>]) + end, ejabberd_odbc:sql_transaction(Host, F). get_user_groups(US) -> Host = element(2, US), DBType = gen_mod:db_type(Host, ?MODULE), - get_user_groups(US, Host, DBType) ++ get_special_users_groups(Host). + get_user_groups(US, Host, DBType) ++ + get_special_users_groups(Host). get_user_groups(US, Host, mnesia) -> case catch mnesia:dirty_read(sr_user, US) of - Rs when is_list(Rs) -> - [Group || #sr_user{group_host = {Group, H}} <- Rs, H == Host]; - _ -> - [] + Rs when is_list(Rs) -> + [Group + || #sr_user{group_host = {Group, H}} <- Rs, H == Host]; + _ -> [] end; get_user_groups(US, Host, odbc) -> SJID = make_jid_s(US), - case catch ejabberd_odbc:sql_query( - Host, ["select grp from sr_user " - "where jid='", SJID, "';"]) of - {selected, ["grp"], Rs} -> - [G || {G} <- Rs]; - _ -> - [] + case catch ejabberd_odbc:sql_query(Host, + [<<"select grp from sr_user where jid='">>, + SJID, <<"';">>]) + of + {selected, [<<"grp">>], Rs} -> [G || [G] <- Rs]; + _ -> [] end. is_group_enabled(Host1, Group1) -> {Host, Group} = split_grouphost(Host1, Group1), case get_group_opts(Host, Group) of - error -> - false; - Opts -> - not lists:member(disabled, Opts) + error -> false; + Opts -> not lists:member(disabled, Opts) end. %% @spec (Host::string(), Group::string(), Opt::atom(), Default) -> OptValue | Default get_group_opt(Host, Group, Opt, Default) -> case get_group_opts(Host, Group) of - error -> - Default; - Opts -> - case lists:keysearch(Opt, 1, Opts) of - {value, {_, Val}} -> - Val; - false -> - Default - end + error -> Default; + Opts -> + case lists:keysearch(Opt, 1, Opts) of + {value, {_, Val}} -> Val; + false -> Default + end end. get_online_users(Host) -> - lists:usort([{U, S} || {U, S, _} <- ejabberd_sm:get_vh_session_list(Host)]). + lists:usort([{U, S} + || {U, S, _} <- ejabberd_sm:get_vh_session_list(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); - false -> - [] - end ++ - case get_group_opt(Host, Group, online_users, false) of - true -> - get_online_users(Host); - false -> - [] - end ++ - get_group_explicit_users(Host, Group). + true -> ejabberd_auth:get_vh_registered_users(Host); + false -> [] + end + ++ + case get_group_opt(Host, Group, online_users, false) of + true -> get_online_users(Host); + false -> [] + end + ++ get_group_explicit_users(Host, Group). get_group_users(Host, Group, GroupOpts) -> case proplists:get_value(all_users, GroupOpts, false) of - true -> - ejabberd_auth:get_vh_registered_users(Host); - false -> - [] - 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()}] + true -> ejabberd_auth:get_vh_registered_users(Host); + false -> [] + end + ++ + case proplists:get_value(online_users, GroupOpts, false) + of + true -> get_online_users(Host); + false -> [] + end + ++ get_group_explicit_users(Host, Group). + get_group_explicit_users(Host, Group) -> - get_group_explicit_users(Host, Group, gen_mod:db_type(Host, ?MODULE)). + get_group_explicit_users(Host, Group, + gen_mod:db_type(Host, ?MODULE)). get_group_explicit_users(Host, Group, mnesia) -> - Read = (catch mnesia:dirty_index_read( - sr_user, - {Group, Host}, - #sr_user.group_host)), + Read = (catch mnesia:dirty_index_read(sr_user, + {Group, Host}, #sr_user.group_host)), case Read of - Rs when is_list(Rs) -> - [R#sr_user.us || R <- Rs]; - _ -> - [] + Rs when is_list(Rs) -> [R#sr_user.us || R <- Rs]; + _ -> [] end; get_group_explicit_users(Host, Group, odbc) -> SGroup = ejabberd_odbc:escape(Group), - case catch ejabberd_odbc:sql_query( - Host, ["select jid from sr_user " - "where grp='", SGroup, "';"]) of - {selected, ["jid"], Rs} -> - lists:map( - fun({JID}) -> - {U, S, _} = jlib:jid_tolower( - jlib:string_to_jid(JID)), - {U, S} - end, Rs); - _ -> - [] + case catch ejabberd_odbc:sql_query(Host, + [<<"select jid from sr_user where grp='">>, + SGroup, <<"';">>]) + of + {selected, [<<"jid">>], Rs} -> + lists:map(fun ([JID]) -> + {U, S, _} = + jlib:jid_tolower(jlib:string_to_jid(JID)), + {U, S} + end, + Rs); + _ -> [] end. get_group_name(Host1, Group1) -> @@ -644,211 +610,233 @@ 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)). - %% 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:filter(fun (Group) -> + get_group_opt(Host, Group, all_users, false) orelse + get_group_opt(Host, Group, online_users, false) + end, + list_groups(Host)). +get_special_users_groups_online(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( - lists:flatmap( - fun({_Group, Opts}) -> - [G || G <- proplists:get_value(displayed_groups, Opts, []), - not lists:member(disabled, Opts)] - end, SelectedGroupsOpts)), - [G || G <- DisplayedGroups, - not lists:member(disabled, proplists:get_value(G, GroupsOpts, []))]. + lists:filter(fun (Group) -> + get_group_opt(Host, Group, online_users, false) + end, + list_groups(Host)). +displayed_groups(GroupsOpts, SelectedGroupsOpts) -> %% Given a list of group names with options, %% for those that have @all@ in memberlist, %% get the list of groups displayed + DisplayedGroups = lists:usort(lists:flatmap(fun + ({_Group, Opts}) -> + [G + || G + <- proplists:get_value(displayed_groups, + Opts, + []), + not + lists:member(disabled, + Opts)] + end, + SelectedGroupsOpts)), + [G + || G <- DisplayedGroups, + not + lists:member(disabled, + proplists:get_value(G, GroupsOpts, []))]. + get_special_displayed_groups(GroupsOpts) -> - Groups = lists:filter( - fun({_Group, Opts}) -> - proplists:get_value(all_users, Opts, false) - end, GroupsOpts), + Groups = lists:filter(fun ({_Group, Opts}) -> + proplists:get_value(all_users, Opts, false) + 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 = get_user_displayed_groups(LUser, LServer, GroupsOpts, - gen_mod:db_type(LServer, ?MODULE)), + Groups = get_user_displayed_groups(LUser, LServer, + GroupsOpts, + gen_mod:db_type(LServer, ?MODULE)), displayed_groups(GroupsOpts, Groups). -get_user_displayed_groups(LUser, LServer, GroupsOpts, mnesia) -> - case catch mnesia:dirty_read(sr_user, {LUser, LServer}) of - Rs when is_list(Rs) -> - [{Group, proplists:get_value(Group, GroupsOpts, [])} || - #sr_user{group_host = {Group, H}} <- Rs, H == LServer]; - _ -> - [] +get_user_displayed_groups(LUser, LServer, GroupsOpts, + mnesia) -> + case catch mnesia:dirty_read(sr_user, {LUser, LServer}) + of + Rs when is_list(Rs) -> + [{Group, proplists:get_value(Group, GroupsOpts, [])} + || #sr_user{group_host = {Group, H}} <- Rs, + H == LServer]; + _ -> [] end; -get_user_displayed_groups(LUser, LServer, GroupsOpts, odbc) -> +get_user_displayed_groups(LUser, LServer, GroupsOpts, + odbc) -> SJID = make_jid_s(LUser, LServer), - case catch ejabberd_odbc:sql_query( - LServer, ["select grp from sr_user " - "where jid='", SJID, "';"]) of - {selected, ["grp"], Rs} -> - [{Group, proplists:get_value(Group, GroupsOpts, [])} || - {Group} <- Rs]; - _ -> - [] + case catch ejabberd_odbc:sql_query(LServer, + [<<"select grp from sr_user where jid='">>, + SJID, <<"';">>]) + of + {selected, [<<"grp">>], Rs} -> + [{Group, proplists:get_value(Group, GroupsOpts, [])} + || [Group] <- Rs]; + _ -> [] end. %% @doc Get the list of groups that are displayed to this user 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)]. + 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)]. is_user_in_group(US, Group, Host) -> - is_user_in_group(US, Group, Host, gen_mod:db_type(Host, ?MODULE)). + is_user_in_group(US, Group, Host, + gen_mod:db_type(Host, ?MODULE)). is_user_in_group(US, Group, Host, mnesia) -> - case catch mnesia:dirty_match_object( - #sr_user{us=US, group_host={Group, Host}}) of - [] -> lists:member(US, get_group_users(Host, Group)); - _ -> true + case catch mnesia:dirty_match_object(#sr_user{us = US, + group_host = {Group, Host}}) + of + [] -> lists:member(US, get_group_users(Host, Group)); + _ -> true end; is_user_in_group(US, Group, Host, odbc) -> SJID = make_jid_s(US), SGroup = ejabberd_odbc:escape(Group), - case catch ejabberd_odbc:sql_query( - Host, ["select * from sr_user where " - "jid='", SJID, "' and grp='", SGroup, "';"]) of - {selected, _, []} -> - lists:member(US, get_group_users(Host, Group)); - _ -> - true + case catch ejabberd_odbc:sql_query(Host, + [<<"select * from sr_user where jid='">>, + SJID, <<"' and grp='">>, SGroup, + <<"';">>]) + of + {selected, _, []} -> + lists:member(US, get_group_users(Host, Group)); + _ -> true end. %% @spec (Host::string(), {User::string(), Server::string()}, Group::string()) -> {atomic, ok} add_user_to_group(Host, US, Group) -> {LUser, LServer} = US, - case ejabberd_regexp:run(LUser, "^@.+@$") of - match -> - GroupOpts = ?MODULE:get_group_opts(Host, Group), - MoreGroupOpts = - case LUser of - "@all@" -> [{all_users, true}]; - "@online@" -> [{online_users, true}]; - _ -> [] - end, - ?MODULE:set_group_opts( - Host, Group, - GroupOpts ++ MoreGroupOpts); - nomatch -> - %% Push this new user to members of groups where this group is displayed - push_user_to_displayed(LUser, LServer, Group, Host, both), - %% Push members of groups that are displayed to this group - push_displayed_to_user(LUser, LServer, Group, Host, both), - add_user_to_group(Host, US, Group, gen_mod:db_type(Host, ?MODULE)) + case ejabberd_regexp:run(LUser, <<"^@.+@$">>) of + match -> + GroupOpts = (?MODULE):get_group_opts(Host, Group), + MoreGroupOpts = case LUser of + <<"@all@">> -> [{all_users, true}]; + <<"@online@">> -> [{online_users, true}]; + _ -> [] + end, + (?MODULE):set_group_opts(Host, Group, + GroupOpts ++ MoreGroupOpts); + nomatch -> + push_user_to_displayed(LUser, LServer, Group, Host, + both), + push_displayed_to_user(LUser, LServer, Group, Host, + both), + add_user_to_group(Host, US, Group, + gen_mod:db_type(Host, ?MODULE)) end. add_user_to_group(Host, US, Group, mnesia) -> R = #sr_user{us = US, group_host = {Group, Host}}, - F = fun() -> - mnesia:write(R) - end, + F = fun () -> mnesia:write(R) end, mnesia:transaction(F); add_user_to_group(Host, US, Group, odbc) -> SJID = make_jid_s(US), SGroup = ejabberd_odbc:escape(Group), - F = fun() -> - odbc_queries:update_t( - "sr_user", - ["jid", "grp"], - [SJID, SGroup], - ["jid='", SJID, "' and grp='", SGroup, "'"]) - end, + F = fun () -> + odbc_queries:update_t(<<"sr_user">>, + [<<"jid">>, <<"grp">>], [SJID, SGroup], + [<<"jid='">>, SJID, <<"' and grp='">>, + SGroup, <<"'">>]) + end, ejabberd_odbc:sql_transaction(Host, F). -push_displayed_to_user(LUser, LServer, Group, Host, Subscription) -> +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]. + 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) -> {LUser, LServer} = US, - case ejabberd_regexp:run(LUser, "^@.+@$") of - match -> - GroupOpts = ?MODULE:get_group_opts(Host, Group), - NewGroupOpts = - case LUser of - "@all@" -> - lists:filter(fun(X) -> X/={all_users,true} end, GroupOpts); - "@online@" -> - lists:filter(fun(X) -> X/={online_users,true} end, GroupOpts) - end, - ?MODULE:set_group_opts(Host, Group, NewGroupOpts); - nomatch -> - Result = remove_user_from_group(Host, US, Group, - gen_mod:db_type(Host, ?MODULE)), - %% 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, Host, 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 + case ejabberd_regexp:run(LUser, <<"^@.+@$">>) of + match -> + GroupOpts = (?MODULE):get_group_opts(Host, Group), + NewGroupOpts = case LUser of + <<"@all@">> -> + lists:filter(fun (X) -> X /= {all_users, true} + end, + GroupOpts); + <<"@online@">> -> + lists:filter(fun (X) -> X /= {online_users, true} + end, + GroupOpts) + end, + (?MODULE):set_group_opts(Host, Group, NewGroupOpts); + nomatch -> + Result = remove_user_from_group(Host, US, Group, + gen_mod:db_type(Host, ?MODULE)), + push_user_to_displayed(LUser, LServer, Group, Host, + remove), + push_displayed_to_user(LUser, LServer, Group, Host, + remove), + Result end. remove_user_from_group(Host, US, Group, mnesia) -> R = #sr_user{us = US, group_host = {Group, Host}}, - F = fun() -> - mnesia:delete_object(R) - end, + F = fun () -> mnesia:delete_object(R) end, mnesia:transaction(F); remove_user_from_group(Host, US, Group, odbc) -> SJID = make_jid_s(US), SGroup = ejabberd_odbc:escape(Group), - F = fun() -> - ejabberd_odbc:sql_query_t( - ["delete from sr_user where jid='", - SJID, "' and grp='", SGroup, "';"]), - ok - end, + F = fun () -> + ejabberd_odbc:sql_query_t([<<"delete from sr_user where jid='">>, + SJID, <<"' and grp='">>, SGroup, + <<"';">>]), + ok + end, ejabberd_odbc:sql_transaction(Host, F). -push_members_to_user(LUser, LServer, Group, Host, Subscription) -> +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). + 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, Server, both) || Group <- Groups]. + [push_user_to_displayed(User, Server, Group, Server, + both) + || Group <- Groups]. remove_user(User, Server) -> push_user_to_members(User, Server, remove). @@ -857,106 +845,115 @@ push_user_to_members(User, Server, Subscription) -> LUser = jlib:nodeprep(User), LServer = jlib:nameprep(Server), GroupsOpts = groups_with_opts(LServer), - SpecialGroups = get_special_displayed_groups(GroupsOpts), - UserGroups = get_user_displayed_groups(LUser, LServer, GroupsOpts), - lists:foreach( - fun(Group) -> - remove_user_from_group(LServer, {LUser, LServer}, Group), - GroupOpts = proplists:get_value(Group, GroupsOpts, []), - GroupName = proplists:get_value(name, GroupOpts, Group), - lists:foreach( - fun({U, S}) -> - push_roster_item(U, S, LUser, LServer, GroupName, Subscription) - end, get_group_users(LServer, Group, GroupOpts)) - end, lists:usort(SpecialGroups++UserGroups)). - -push_user_to_displayed(LUser, LServer, Group, Host, Subscription) -> + SpecialGroups = + get_special_displayed_groups(GroupsOpts), + UserGroups = get_user_displayed_groups(LUser, LServer, + GroupsOpts), + lists:foreach(fun (Group) -> + remove_user_from_group(LServer, {LUser, LServer}, + Group), + GroupOpts = proplists:get_value(Group, GroupsOpts, + []), + GroupName = proplists:get_value(name, GroupOpts, + Group), + lists:foreach(fun ({U, S}) -> + push_roster_item(U, S, LUser, + LServer, + GroupName, + Subscription) + end, + get_group_users(LServer, Group, + GroupOpts)) + end, + lists:usort(SpecialGroups ++ UserGroups)). + +push_user_to_displayed(LUser, LServer, Group, Host, + Subscription) -> GroupsOpts = groups_with_opts(Host), GroupOpts = proplists:get_value(Group, GroupsOpts, []), GroupName = proplists:get_value(name, GroupOpts, Group), - DisplayedToGroupsOpts = displayed_to_groups(Group, Host), - [push_user_to_group(LUser, LServer, GroupD, Host, GroupName, Subscription) || {GroupD, _Opts} <- 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) - end, get_group_users(Host, Group)). + DisplayedToGroupsOpts = displayed_to_groups(Group, + Host), + [push_user_to_group(LUser, LServer, GroupD, Host, + GroupName, Subscription) + || {GroupD, _Opts} <- 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) + 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), - lists:filter( - fun({_Group, Opts}) -> - lists:member(GroupName, proplists:get_value(displayed_groups, Opts, [])) - end, GroupsOpts). + lists:filter(fun ({_Group, Opts}) -> + lists:member(GroupName, + proplists:get_value(displayed_groups, + Opts, [])) + end, + GroupsOpts). push_item(User, Server, From, Item) -> - %% It was - %% ejabberd_sm:route(jlib:make_jid("", "", ""), - %% jlib:make_jid(User, Server, "") - %% why? - ejabberd_sm:route(From, jlib:make_jid(User, Server, ""), - {xmlelement, "broadcast", [], - [{item, - Item#roster.jid, - Item#roster.subscription}]}), - Stanza = jlib:iq_to_xml( - #iq{type = set, xmlns = ?NS_ROSTER, - id = "push" ++ randoms:get_string(), - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_ROSTER}], - [item_to_xml(Item)]}]}), - lists:foreach( - fun(Resource) -> - JID = jlib:make_jid(User, Server, Resource), - 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, + ejabberd_sm:route(From, + jlib:make_jid(User, Server, <<"">>), + {broadcast, {item, Item#roster.jid, + Item#roster.subscription}}), + 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 = jlib:make_jid(User, Server, Resource), + 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). + push_item(User, Server, + jlib:make_jid(<<"">>, Server, <<"">>), Item). item_to_xml(Item) -> - Attrs1 = [{"jid", jlib:jid_to_string(Item#roster.jid)}], + Attrs1 = [{<<"jid">>, + jlib:jid_to_string(Item#roster.jid)}], Attrs2 = case Item#roster.name of - "" -> - Attrs1; - Name -> - [{"name", Name} | Attrs1] + <<"">> -> 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] + 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 + out -> [{<<"ask">>, <<"subscribe">>} | Attrs3]; + both -> [{<<"ask">>, <<"subscribe">>} | Attrs3]; + _ -> Attrs3 end, - SubEls1 = lists:map(fun(G) -> - {xmlelement, "group", [], [{xmlcdata, G}]} - end, Item#roster.groups), + SubEls1 = lists:map(fun (G) -> + #xmlel{name = <<"group">>, attrs = [], + children = [{xmlcdata, G}]} + end, + Item#roster.groups), SubEls = SubEls1 ++ Item#roster.xs, - {xmlelement, "item", Attrs4, SubEls}. + #xmlel{name = <<"item">>, attrs = Attrs4, + children = SubEls}. ask_to_pending(subscribe) -> out; ask_to_pending(unsubscribe) -> none; @@ -965,47 +962,41 @@ ask_to_pending(Ask) -> Ask. user_available(New) -> LUser = New#jid.luser, LServer = New#jid.lserver, - Resources = ejabberd_sm:get_user_resources(LUser, 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 -> - %% This is a simplification - we ignore he 'display' - %% property - @online@ is always reflective. - OnlineGroups = get_special_users_groups_online(LServer), - lists:foreach( - fun(OG) -> - ?DEBUG("user_available: pushing ~p @ ~p grp ~p", - [LUser, LServer, OG ]), - push_user_to_displayed(LUser, LServer, OG, LServer, both) - end, OnlineGroups); - _ -> - ok + %% first session for this user + 1 -> + OnlineGroups = get_special_users_groups_online(LServer), + lists:foreach(fun (OG) -> + ?DEBUG("user_available: pushing ~p @ ~p grp ~p", + [LUser, LServer, OG]), + push_user_to_displayed(LUser, LServer, OG, + LServer, both) + end, + OnlineGroups); + _ -> ok end. unset_presence(LUser, LServer, Resource, Status) -> - Resources = ejabberd_sm:get_user_resources(LUser, LServer), - ?DEBUG("unset_presence for ~p @ ~p / ~p -> ~p (~p resources)", + Resources = ejabberd_sm:get_user_resources(LUser, + LServer), + ?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, LServer, 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 + 0 -> + OnlineGroups = get_special_users_groups_online(LServer), + lists:foreach(fun (OG) -> + push_user_to_displayed(LUser, LServer, OG, + LServer, remove), + push_displayed_to_user(LUser, LServer, OG, + LServer, remove) + end, + OnlineGroups); + _ -> ok end. %%--------------------- @@ -1013,275 +1004,332 @@ unset_presence(LUser, LServer, Resource, Status) -> %%--------------------- webadmin_menu(Acc, _Host, Lang) -> - [{"shared-roster", ?T("Shared Roster Groups")} | Acc]. + [{<<"shared-roster">>, ?T(<<"Shared Roster Groups">>)} + | Acc]. webadmin_page(_, Host, - #request{us = _US, - path = ["shared-roster"], - q = Query, - lang = Lang} = _Request) -> + #request{us = _US, path = [<<"shared-roster">>], + q = Query, lang = Lang} = + _Request) -> Res = list_shared_roster_groups(Host, Query, Lang), {stop, Res}; - webadmin_page(_, Host, - #request{us = _US, - path = ["shared-roster", Group], - q = Query, - lang = Lang} = _Request) -> + #request{us = _US, path = [<<"shared-roster">>, Group], + q = Query, lang = Lang} = + _Request) -> Res = shared_roster_group(Host, Group, Query, Lang), {stop, Res}; - webadmin_page(Acc, _, _) -> Acc. list_shared_roster_groups(Host, Query, Lang) -> Res = list_sr_groups_parse_query(Host, Query), - SRGroups = ?MODULE:list_groups(Host), - FGroups = - ?XAE("table", [], - [?XE("tbody", - lists:map( - fun(Group) -> - ?XE("tr", - [?XE("td", [?INPUT("checkbox", "selected", - Group)]), - ?XE("td", [?AC(Group ++ "/", Group)]) - ] - ) - end, lists:sort(SRGroups)) ++ - [?XE("tr", - [?X("td"), - ?XE("td", [?INPUT("text", "namenew", "")]), - ?XE("td", [?INPUTT("submit", "addnew", "Add New")]) - ] - )] - )]), - ?H1GL(?T("Shared Roster Groups"), "modsharedroster", "mod_shared_roster") ++ - case Res of - ok -> [?XREST("Submitted")]; - error -> [?XREST("Bad format")]; - nothing -> [] - end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], - [FGroups, - ?BR, - ?INPUTT("submit", "delete", "Delete Selected") - ]) - ]. + SRGroups = (?MODULE):list_groups(Host), + FGroups = (?XAE(<<"table">>, [], + [?XE(<<"tbody">>, + (lists:map(fun (Group) -> + ?XE(<<"tr">>, + [?XE(<<"td">>, + [?INPUT(<<"checkbox">>, + <<"selected">>, + Group)]), + ?XE(<<"td">>, + [?AC(<<Group/binary, "/">>, + Group)])]) + end, + lists:sort(SRGroups)) + ++ + [?XE(<<"tr">>, + [?X(<<"td">>), + ?XE(<<"td">>, + [?INPUT(<<"text">>, <<"namenew">>, + <<"">>)]), + ?XE(<<"td">>, + [?INPUTT(<<"submit">>, <<"addnew">>, + <<"Add New">>)])])]))])), + (?H1GL((?T(<<"Shared Roster Groups">>)), + <<"modsharedroster">>, <<"mod_shared_roster">>)) + ++ + case Res of + ok -> [?XREST(<<"Submitted">>)]; + error -> [?XREST(<<"Bad format">>)]; + nothing -> [] + end + ++ + [?XAE(<<"form">>, + [{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}], + [FGroups, ?BR, + ?INPUTT(<<"submit">>, <<"delete">>, + <<"Delete Selected">>)])]. list_sr_groups_parse_query(Host, Query) -> - case lists:keysearch("addnew", 1, Query) of - {value, _} -> - list_sr_groups_parse_addnew(Host, Query); - _ -> - case lists:keysearch("delete", 1, Query) of - {value, _} -> - list_sr_groups_parse_delete(Host, Query); - _ -> - nothing - end + case lists:keysearch(<<"addnew">>, 1, Query) of + {value, _} -> list_sr_groups_parse_addnew(Host, Query); + _ -> + case lists:keysearch(<<"delete">>, 1, Query) of + {value, _} -> list_sr_groups_parse_delete(Host, Query); + _ -> nothing + end end. list_sr_groups_parse_addnew(Host, Query) -> - case lists:keysearch("namenew", 1, Query) of - {value, {_, Group}} when Group /= "" -> - ?MODULE:create_group(Host, Group), - ok; - _ -> - error + case lists:keysearch(<<"namenew">>, 1, Query) of + {value, {_, Group}} when Group /= <<"">> -> + (?MODULE):create_group(Host, Group), ok; + _ -> error end. list_sr_groups_parse_delete(Host, Query) -> - SRGroups = ?MODULE:list_groups(Host), - lists:foreach( - fun(Group) -> - case lists:member({"selected", Group}, Query) of - true -> - ?MODULE:delete_group(Host, Group); - _ -> - ok - end - end, SRGroups), + SRGroups = (?MODULE):list_groups(Host), + lists:foreach(fun (Group) -> + case lists:member({<<"selected">>, Group}, Query) of + true -> (?MODULE):delete_group(Host, Group); + _ -> ok + end + end, + SRGroups), ok. - shared_roster_group(Host, Group, Query, Lang) -> - Res = shared_roster_group_parse_query(Host, Group, Query), - GroupOpts = ?MODULE:get_group_opts(Host, Group), - Name = get_opt(GroupOpts, name, ""), - Description = get_opt(GroupOpts, description, ""), + Res = shared_roster_group_parse_query(Host, Group, + Query), + GroupOpts = (?MODULE):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), - %%Disabled = false, - DisplayedGroups = get_opt(GroupOpts, displayed_groups, []), - Members = ?MODULE:get_group_explicit_users(Host, Group), - FMembers = - if - AllUsers -> - "@all@\n"; - true -> - [] - end ++ - if - OnlineUsers -> - "@online@\n"; - true -> - [] - end ++ - [[us_to_list(Member), $\n] || Member <- Members], - FDisplayedGroups = [[DG, $\n] || DG <- DisplayedGroups], - DescNL = length(ejabberd_regexp:split(Description, "\n")), - FGroup = - ?XAE("table", [{"class", "withtextareas"}], - [?XE("tbody", - [?XE("tr", - [?XCT("td", "Name:"), - ?XE("td", [?INPUT("text", "name", Name)]) - ] - ), - ?XE("tr", - [?XCT("td", "Description:"), - ?XE("td", [ - ?TEXTAREA("description", integer_to_list(lists:max([3, DescNL])), "20", Description) - ] - ) - ] - ), - ?XE("tr", - [?XCT("td", "Members:"), - ?XE("td", [ - ?TEXTAREA("members", integer_to_list(lists:max([3, length(FMembers)])), "20", FMembers) - ] - ) - ] - ), - ?XE("tr", - [?XCT("td", "Displayed Groups:"), - ?XE("td", [ - ?TEXTAREA("dispgroups", integer_to_list(lists:max([3, length(FDisplayedGroups)])), "20", FDisplayedGroups) - ] - ) - ] - )] - )]), - ?H1GL(?T("Shared Roster Groups"), "modsharedroster", "mod_shared_roster") ++ - [?XC("h2", ?T("Group ") ++ Group)] ++ + DisplayedGroups = get_opt(GroupOpts, displayed_groups, + []), + Members = (?MODULE):get_group_explicit_users(Host, + Group), + FMembers = iolist_to_binary( + [if AllUsers -> <<"@all@\n">>; + true -> <<"">> + end, + if OnlineUsers -> <<"@online@\n">>; + true -> <<"">> + end, + [[us_to_list(Member), $\n] || Member <- Members]]), + FDisplayedGroups = [<<DG/binary, $\n>> || DG <- DisplayedGroups], + DescNL = length(ejabberd_regexp:split(Description, + <<"\n">>)), + FGroup = (?XAE(<<"table">>, + [{<<"class">>, <<"withtextareas">>}], + [?XE(<<"tbody">>, + [?XE(<<"tr">>, + [?XCT(<<"td">>, <<"Name:">>), + ?XE(<<"td">>, + [?INPUT(<<"text">>, <<"name">>, Name)])]), + ?XE(<<"tr">>, + [?XCT(<<"td">>, <<"Description:">>), + ?XE(<<"td">>, + [?TEXTAREA(<<"description">>, + jlib:integer_to_binary(lists:max([3, + DescNL])), + <<"20">>, Description)])]), + ?XE(<<"tr">>, + [?XCT(<<"td">>, <<"Members:">>), + ?XE(<<"td">>, + [?TEXTAREA(<<"members">>, + jlib:integer_to_binary(lists:max([3, + byte_size(FMembers)])), + <<"20">>, FMembers)])]), + ?XE(<<"tr">>, + [?XCT(<<"td">>, <<"Displayed Groups:">>), + ?XE(<<"td">>, + [?TEXTAREA(<<"dispgroups">>, + jlib:integer_to_binary(lists:max([3, length(FDisplayedGroups)])), + <<"20">>, + list_to_binary(FDisplayedGroups))])])])])), + (?H1GL((?T(<<"Shared Roster Groups">>)), + <<"modsharedroster">>, <<"mod_shared_roster">>)) + ++ + [?XC(<<"h2">>, <<(?T(<<"Group ">>))/binary, Group/binary>>)] ++ case Res of - ok -> [?XREST("Submitted")]; - error -> [?XREST("Bad format")]; - nothing -> [] - end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], - [FGroup, - ?BR, - ?INPUTT("submit", "submit", "Submit") - ]) - ]. + ok -> [?XREST(<<"Submitted">>)]; + error -> [?XREST(<<"Bad format">>)]; + nothing -> [] + end + ++ + [?XAE(<<"form">>, + [{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}], + [FGroup, ?BR, + ?INPUTT(<<"submit">>, <<"submit">>, <<"Submit">>)])]. shared_roster_group_parse_query(Host, Group, Query) -> - case lists:keysearch("submit", 1, Query) of - {value, _} -> - {value, {_, Name}} = lists:keysearch("name", 1, Query), - {value, {_, Description}} = lists:keysearch("description", 1, Query), - {value, {_, SMembers}} = lists:keysearch("members", 1, Query), - {value, {_, SDispGroups}} = lists:keysearch("dispgroups", 1, Query), - NameOpt = - if - Name == "" -> []; - true -> [{name, Name}] - end, - DescriptionOpt = - if - Description == "" -> []; - true -> [{description, Description}] - end, - DispGroups = string:tokens(SDispGroups, "\r\n"), - DispGroupsOpt = - if - DispGroups == [] -> []; - true -> [{displayed_groups, DispGroups}] - end, - - OldMembers = ?MODULE:get_group_explicit_users( - Host, Group), - SJIDs = string:tokens(SMembers, ", \r\n"), - NewMembers = - lists:foldl( - fun(_SJID, error) -> error; - (SJID, USs) -> - case SJID of - "@all@" -> - USs; - "@online@" -> - USs; - _ -> - case jlib:string_to_jid(SJID) of - JID when is_record(JID, jid) -> - [{JID#jid.luser, JID#jid.lserver} | USs]; - error -> - error - end - end - end, [], SJIDs), - AllUsersOpt = - case lists:member("@all@", SJIDs) of - true -> [{all_users, true}]; - false -> [] - end, - OnlineUsersOpt = - case lists:member("@online@", SJIDs) of - true -> [{online_users, true}]; - false -> [] - end, - - ?MODULE:set_group_opts( - Host, Group, - NameOpt ++ DispGroupsOpt ++ DescriptionOpt ++ AllUsersOpt ++ OnlineUsersOpt), - - if - NewMembers == error -> error; - true -> - AddedMembers = NewMembers -- OldMembers, - RemovedMembers = OldMembers -- NewMembers, - lists:foreach( - fun(US) -> - ?MODULE:remove_user_from_group( - Host, US, Group) - end, RemovedMembers), - lists:foreach( - fun(US) -> - ?MODULE:add_user_to_group( - Host, US, Group) - end, AddedMembers), - ok - end; - _ -> - nothing + case lists:keysearch(<<"submit">>, 1, Query) of + {value, _} -> + {value, {_, Name}} = lists:keysearch(<<"name">>, 1, + Query), + {value, {_, Description}} = + lists:keysearch(<<"description">>, 1, Query), + {value, {_, SMembers}} = lists:keysearch(<<"members">>, + 1, Query), + {value, {_, SDispGroups}} = + lists:keysearch(<<"dispgroups">>, 1, Query), + NameOpt = if Name == <<"">> -> []; + true -> [{name, Name}] + end, + DescriptionOpt = if Description == <<"">> -> []; + true -> [{description, Description}] + end, + DispGroups = str:tokens(SDispGroups, <<"\r\n">>), + DispGroupsOpt = if DispGroups == [] -> []; + true -> [{displayed_groups, DispGroups}] + end, + OldMembers = (?MODULE):get_group_explicit_users(Host, + Group), + SJIDs = str:tokens(SMembers, <<", \r\n">>), + NewMembers = lists:foldl(fun (_SJID, error) -> error; + (SJID, USs) -> + case SJID of + <<"@all@">> -> USs; + <<"@online@">> -> USs; + _ -> + case jlib:string_to_jid(SJID) + of + JID + when is_record(JID, + jid) -> + [{JID#jid.luser, + JID#jid.lserver} + | USs]; + error -> error + end + end + end, + [], SJIDs), + AllUsersOpt = case lists:member(<<"@all@">>, SJIDs) of + true -> [{all_users, true}]; + false -> [] + end, + OnlineUsersOpt = case lists:member(<<"@online@">>, + SJIDs) + of + true -> [{online_users, true}]; + false -> [] + end, + (?MODULE):set_group_opts(Host, Group, + NameOpt ++ + DispGroupsOpt ++ + DescriptionOpt ++ + AllUsersOpt ++ OnlineUsersOpt), + if NewMembers == error -> error; + true -> + AddedMembers = NewMembers -- OldMembers, + RemovedMembers = OldMembers -- NewMembers, + lists:foreach(fun (US) -> + (?MODULE):remove_user_from_group(Host, + US, + Group) + end, + RemovedMembers), + lists:foreach(fun (US) -> + (?MODULE):add_user_to_group(Host, US, + Group) + end, + AddedMembers), + ok + end; + _ -> nothing end. get_opt(Opts, Opt, Default) -> case lists:keysearch(Opt, 1, Opts) of - {value, {_, Val}} -> - Val; - false -> - Default + {value, {_, Val}} -> Val; + false -> Default end. us_to_list({User, Server}) -> - jlib:jid_to_string({User, Server, ""}). + jlib:jid_to_string({User, Server, <<"">>}). split_grouphost(Host, Group) -> - case string:tokens(Group, "@") of - [GroupName, HostName] -> - {HostName, GroupName}; - [_] -> - {Host, Group} + case str:tokens(Group, <<"@">>) of + [GroupName, HostName] -> {HostName, GroupName}; + [_] -> {Host, Group} end. make_jid_s(U, S) -> - ejabberd_odbc:escape( - jlib:jid_to_string( - jlib:jid_tolower( - jlib:make_jid(U, S, "")))). + ejabberd_odbc:escape(jlib:jid_to_string(jlib:jid_tolower(jlib:make_jid(U, + S, + <<"">>)))). + +make_jid_s({U, S}) -> make_jid_s(U, S). + +opts_to_binary(Opts) -> + lists:map( + fun({name, Name}) -> + {name, iolist_to_binary(Name)}; + ({description, Desc}) -> + {description, iolist_to_binary(Desc)}; + ({displayed_groups, Gs}) -> + {displayed_groups, [iolist_to_binary(G) || G <- Gs]}; + (Opt) -> + Opt + end, Opts). + +update_tables() -> + update_sr_group_table(), + update_sr_user_table(). + +update_sr_group_table() -> + Fields = record_info(fields, sr_group), + case mnesia:table_info(sr_group, attributes) of + Fields -> + ejabberd_config:convert_table_to_binary( + sr_group, Fields, set, + fun(#sr_group{group_host = {G, _}}) -> G end, + fun(#sr_group{group_host = {G, H}, + opts = Opts} = R) -> + R#sr_group{group_host = {iolist_to_binary(G), + iolist_to_binary(H)}, + opts = opts_to_binary(Opts)} + end); + _ -> + ?INFO_MSG("Recreating sr_group table", []), + mnesia:transform_table(sr_group, ignore, Fields) + end. + +update_sr_user_table() -> + Fields = record_info(fields, sr_user), + case mnesia:table_info(sr_user, attributes) of + Fields -> + ejabberd_config:convert_table_to_binary( + sr_user, Fields, bag, + fun(#sr_user{us = {U, _}}) -> U end, + fun(#sr_user{us = {U, S}, group_host = {G, H}} = R) -> + R#sr_user{us = {iolist_to_binary(U), iolist_to_binary(S)}, + group_host = {iolist_to_binary(G), + iolist_to_binary(H)}} + end); + _ -> + ?INFO_MSG("Recreating sr_user table", []), + mnesia:transform_table(sr_user, ignore, Fields) + end. -make_jid_s({U, S}) -> - make_jid_s(U, S). +export(_Server) -> + [{sr_group, + fun(Host, #sr_group{group_host = {Group, LServer}, opts = Opts}) + when LServer == Host -> + SGroup = ejabberd_odbc:escape(Group), + SOpts = ejabberd_odbc:encode_term(Opts), + [[<<"delete from sr_group where name='">>, Group, <<"';">>], + [<<"insert into sr_group(name, opts) values ('">>, + SGroup, <<"', '">>, SOpts, <<"');">>]]; + (_Host, _R) -> + [] + end}, + {sr_user, + fun(Host, #sr_user{us = {U, S}, group_host = {Group, LServer}}) + when LServer == Host -> + SGroup = ejabberd_odbc:escape(Group), + SJID = ejabberd_odbc:escape( + jlib:jid_to_string( + jlib:jid_tolower( + jlib:make_jid(U, S, <<"">>)))), + [[<<"delete from sr_user where jid='">>, SJID, + <<"'and grp='">>, Group, <<"';">>], + [<<"insert into sr_user(jid, grp) values ('">>, + SJID, <<"', '">>, SGroup, <<"');">>]]; + (_Host, _R) -> + [] + end}]. |