diff options
author | tmallard <tmallard@null> | 2005-04-17 18:08:34 +0000 |
---|---|---|
committer | tmallard <tmallard@null> | 2005-04-17 18:08:34 +0000 |
commit | 374446f8471747c878cdaf760c4bb37d17493ab7 (patch) | |
tree | e91bac5669555dcf33627e4745b04236f743126d /src/web/ejabberd_web_admin.erl | |
parent | * src/ejabberd_c2s.erl: Send new id for each new stream inside one (diff) |
Merged the Process One contributions ( Virtual Hosting )
SVN Revision: 307
Diffstat (limited to 'src/web/ejabberd_web_admin.erl')
-rw-r--r-- | src/web/ejabberd_web_admin.erl | 448 |
1 files changed, 318 insertions, 130 deletions
diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 7e396b6ac..314b98380 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -5,8 +5,8 @@ %%% Created : 9 Apr 2004 by Alexey Shchepin <alexey@sevcom.net> %%% Id : $Id$ %%%---------------------------------------------------------------------- -%%% Copyright (c) 2004 Alexey Shchepin -%%% Copyright (c) 2004 Process One +%%% Copyright (c) 2004-2005 Alexey Shchepin +%%% Copyright (c) 2004-2005 Process One %%%---------------------------------------------------------------------- -module(ejabberd_web_admin). @@ -119,7 +119,7 @@ make_xhtml(Els, Lang) -> [?XE("tbody", [?XE("tr", [?XCT("td", - "ejabberd (c) 2002-2005 Alexey Shchepin, 2004 Process One") + "ejabberd (c) 2002-2005 Alexey Shchepin, 2004-2005 Process One") ])]) ])])])])])]) ]}}. @@ -304,13 +304,13 @@ input[type=submit] { } textarea { - border: 1px solid #93a6c7; - color: #556655; - background-color: #ffffff; + border: 1px solid #d6760e; + color: #723202; + background-color: #fff2e8; vertical-align: middle; margin-top: 7px; - margin-left: 7px; - margin-right: 7px; + /*margin-left: 7px; + margin-right: 7px;*/ margin-bottom: 5px; padding: 0.1em; } @@ -494,10 +494,10 @@ empty() -> jlib:decode_base64( "R0lGODlhAQABAIAAAP///////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAh+QQBCgABACwAAAAAAQABAAACAkwBADs="). -process_admin(#request{user = User, - path = [], - q = Query, - lang = Lang} = Request) -> +process_admin(#request{us = US, + path = [], + q = Query, + lang = Lang} = Request) -> make_xhtml([?XCT("h1", "ejabberd administration"), ?XE("ul", [?LI([?ACT("acls/", "Access Control Lists"), ?C(" "), @@ -511,31 +511,31 @@ process_admin(#request{user = User, ]) ], Lang); -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["style.css"], q = Query, lang = Lang} = Request) -> {200, [{"Content-Type", "text/css"}], css()}; -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["logo.png"], q = Query, lang = Lang} = Request) -> {200, [{"Content-Type", "image/png"}], logo()}; -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["logo-fill.png"], q = Query, lang = Lang} = Request) -> {200, [{"Content-Type", "image/png"}], logo_fill()}; -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["1x1tr.gif"], q = Query, lang = Lang} = Request) -> {200, [{"Content-Type", "image/gif"}], empty()}; -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["acls-raw"], q = Query, lang = Lang} = Request) -> @@ -578,7 +578,7 @@ process_admin(#request{user = User, ], Lang); process_admin(#request{method = Method, - user = User, + us = US, path = ["acls"], q = Query, lang = Lang} = Request) -> @@ -618,7 +618,7 @@ process_admin(#request{method = Method, ]) ], Lang); -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["access-raw"], q = Query, lang = Lang} = Request) -> @@ -686,7 +686,7 @@ process_admin(#request{user = User, ], Lang); process_admin(#request{method = Method, - user = User, + us = US, path = ["access"], q = Query, lang = Lang} = Request) -> @@ -722,7 +722,7 @@ process_admin(#request{method = Method, ], Lang); process_admin(#request{method = Method, - user = User, + us = US, path = ["access", SName], q = Query, lang = Lang} = Request) -> @@ -761,63 +761,63 @@ process_admin(#request{method = Method, ]) ], Lang); -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["users"], q = Query, lang = Lang} = Request) -> Res = list_users(Query, Lang), make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Lang); -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["users", Diap], q = Query, lang = Lang} = Request) -> Res = list_users_in_diapason(Diap, Lang), make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Lang); -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["online-users"], q = Query, lang = Lang} = Request) -> Res = list_online_users(Lang), make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Lang); -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["stats"], q = Query, lang = Lang} = Request) -> Res = get_stats(Lang), make_xhtml([?XCT("h1", "ejabberd stats")] ++ Res, Lang); -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["user", U], q = Query, lang = Lang} = Request) -> Res = user_info(U, Query, Lang), make_xhtml(Res, Lang); -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["user", U, "queue"], q = Query, lang = Lang} = Request) -> Res = user_queue(U, Query, Lang), make_xhtml(Res, Lang); -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["user", U, "roster"], q = Query, lang = Lang} = Request) -> Res = user_roster(U, Query, Lang, true), make_xhtml(Res, Lang); -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["nodes"], q = Query, lang = Lang} = Request) -> Res = get_nodes(Lang), make_xhtml(Res, Lang); -process_admin(#request{user = User, +process_admin(#request{us = US, path = ["node", SNode | NPath], q = Query, lang = Lang} = Request) -> @@ -829,6 +829,20 @@ process_admin(#request{user = User, make_xhtml(Res, Lang) end; +process_admin(#request{us = US, + path = ["shared-roster"], + q = Query, + lang = Lang} = Request) -> + Res = list_shared_roster_groups(Query, Lang), + make_xhtml(Res, Lang); + +process_admin(#request{us = US, + path = ["shared-roster", Group], + q = Query, + lang = Lang} = Request) -> + Res = shared_roster_group(Group, Query, Lang), + make_xhtml(Res, Lang); + process_admin(#request{lang = Lang}) -> setelement(1, make_xhtml([?XC("h1", "Not found")], Lang), 404). @@ -1065,7 +1079,7 @@ parse_access_rule(Text) -> list_users(Query, Lang) -> Res = list_users_parse_query(Query), Users = ejabberd_auth:dirty_get_registered_users(), - SUsers = lists:sort(Users), + SUsers = lists:sort([{S, U} || {U, S} <- Users]), FUsers = case length(SUsers) of N when N =< 100 -> @@ -1077,11 +1091,12 @@ list_users(Query, Lang) -> fun(K) -> L = K + M - 1, Node = integer_to_list(K) ++ "-" ++ integer_to_list(L), - Last = if L < N -> lists:nth(L, SUsers); - true -> lists:last(SUsers) + Last = if L < N -> su_to_list(lists:nth(L, SUsers)); + true -> su_to_list(lists:last(SUsers)) end, Name = - lists:nth(K, SUsers) ++ [$\s, 226, 128, 148, $\s] ++ + su_to_list(lists:nth(K, SUsers)) ++ + [$\s, 226, 128, 148, $\s] ++ Last, [?AC(Node ++ "/", Name), ?BR] end, lists:seq(1, N, M)) @@ -1131,7 +1146,7 @@ list_users_parse_query(Query) -> list_users_in_diapason(Diap, Lang) -> Users = ejabberd_auth:dirty_get_registered_users(), - SUsers = lists:sort(Users), + SUsers = lists:sort([{S, U} || {U, S} <- Users]), {ok, [S1, S2]} = regexp:split(Diap, "-"), N1 = list_to_integer(S1), N2 = list_to_integer(S2), @@ -1147,14 +1162,15 @@ list_given_users(Users, Prefix, Lang) -> ?XCT("td", "Last Activity")])]), ?XE("tbody", lists:map( - fun(User) -> - QueueLen = length(mnesia:dirty_read({offline_msg, User})), + fun(SU = {Server, User}) -> + US = {User, Server}, + QueueLen = length(mnesia:dirty_read({offline_msg, US})), FQueueLen = [?AC(Prefix ++ "user/" ++ User ++ "/queue/", integer_to_list(QueueLen))], FLast = - case ejabberd_sm:get_user_resources(User) of + case ejabberd_sm:get_user_resources(User, Server) of [] -> - case mnesia:dirty_read({last_activity, User}) of + case mnesia:dirty_read({last_activity, US}) of [] -> ?T("Never"); [E] -> @@ -1173,13 +1189,20 @@ list_given_users(Users, Prefix, Lang) -> ?T("Online") end, ?XE("tr", - [?XE("td", [?AC(Prefix ++ "user/" ++ User ++ "/", - User)]), + [?XE("td", [?AC(Prefix ++ "user/" ++ + us_to_list(US) ++ "/", + us_to_list(US))]), ?XE("td", FQueueLen), ?XC("td", FLast)]) end, Users) )]). +us_to_list({User, Server}) -> + jlib:jid_to_string({User, Server, ""}). + +su_to_list({Server, User}) -> + jlib:jid_to_string({User, Server, ""}). + get_stats(Lang) -> OnlineUsers = mnesia:table_info(presence, size), @@ -1206,17 +1229,20 @@ get_stats(Lang) -> list_online_users(_Lang) -> - Users = lists:map(fun({U, R}) -> U end, - ejabberd_sm:dirty_get_sessions_list()), + Users = [{S, U} || {U, S, R} <- ejabberd_sm:dirty_get_sessions_list()], SUsers = lists:usort(Users), lists:flatmap( - fun(U) -> - [?AC("../user/" ++ U ++ "/", U), ?BR] + fun(SU) -> + [?AC("../user/" ++ su_to_list(SU) ++ "/", su_to_list(SU)), ?BR] end, SUsers). -user_info(User, Query, Lang) -> - Res = user_parse_query(User, Query), - Resources = ejabberd_sm:get_user_resources(User), +user_info(SUser, Query, Lang) -> + UJID = jlib:string_to_jid(SUser), + User = UJID#jid.user, + Server = UJID#jid.server, + US = {UJID#jid.luser, UJID#jid.lserver}, + Res = user_parse_query(User, Server, Query), + Resources = ejabberd_sm:get_user_resources(User, Server), FResources = case Resources of [] -> @@ -1227,13 +1253,13 @@ user_info(User, Query, Lang) -> ?LI([?C(R)]) end, lists:sort(Resources)))] end, - Password = ejabberd_auth:get_password_s(User), + Password = ejabberd_auth:get_password_s(User, Server), FPassword = [?INPUT("password", "password", Password), ?C(" "), ?INPUTT("submit", "chpassword", "Change Password")], - QueueLen = length(mnesia:dirty_read({offline_msg, User})), + QueueLen = length(mnesia:dirty_read({offline_msg, US})), FQueueLen = [?AC("queue/", integer_to_list(QueueLen))], - [?XC("h1", ?T("User ") ++ User)] ++ + [?XC("h1", ?T("User ") ++ us_to_list(US))] ++ case Res of ok -> [?CT("submitted"), ?P]; error -> [?CT("bad format"), ?P]; @@ -1247,14 +1273,14 @@ user_info(User, Query, Lang) -> [?BR, ?INPUTT("submit", "removeuser", "Remove User")])]. -user_parse_query(User, Query) -> +user_parse_query(User, Server, Query) -> case lists:keysearch("chpassword", 1, Query) of {value, _} -> case lists:keysearch("password", 1, Query) of {value, {_, undefined}} -> error; {value, {_, Password}} -> - ejabberd_auth:set_password(User, Password), + ejabberd_auth:set_password(User, Server, Password), ok; _ -> error @@ -1262,7 +1288,7 @@ user_parse_query(User, Query) -> _ -> case lists:keysearch("removeuser", 1, Query) of {value, _} -> - ejabberd_auth:remove_user(User), + ejabberd_auth:remove_user(User, Server), ok; false -> nothing @@ -1270,12 +1296,16 @@ user_parse_query(User, Query) -> end. -user_queue(User, Query, Lang) -> - Res = user_queue_parse_query(User, Query), - Msgs = lists:keysort(3, mnesia:dirty_read({offline_msg, User})), +user_queue(SUser, Query, Lang) -> + UJID = jlib:string_to_jid(SUser), + User = UJID#jid.user, + Server = UJID#jid.server, + US = {UJID#jid.luser, UJID#jid.lserver}, + Res = user_queue_parse_query(US, Query), + Msgs = lists:keysort(3, mnesia:dirty_read({offline_msg, US})), FMsgs = lists:map( - fun({offline_msg, _User, TimeStamp, _Expire, From, To, + fun({offline_msg, _US, TimeStamp, _Expire, From, To, {xmlelement, Name, Attrs, Els}} = Msg) -> ID = jlib:encode_base64(binary_to_list(term_to_binary(Msg))), {{Year, Month, Day}, {Hour, Minute, Second}} = @@ -1298,7 +1328,8 @@ user_queue(User, Query, Lang) -> ?XAE("td", [{"class", "valign"}], [?XC("pre", FPacket)])] ) end, Msgs), - [?XC("h1", io_lib:format(?T("~s offline messages queue"), [User]))] ++ + [?XC("h1", io_lib:format(?T("~s offline messages queue"), + [us_to_list(US)]))] ++ case Res of ok -> [?CT("submitted"), ?P]; error -> [?CT("bad format"), ?P]; @@ -1319,10 +1350,10 @@ user_queue(User, Query, Lang) -> ?INPUTT("submit", "delete", "Delete Selected") ])]. -user_queue_parse_query(User, Query) -> +user_queue_parse_query(US, Query) -> case lists:keysearch("delete", 1, Query) of {value, _} -> - Msgs = lists:keysort(3, mnesia:dirty_read({offline_msg, User})), + Msgs = lists:keysort(3, mnesia:dirty_read({offline_msg, US})), F = fun() -> lists:foreach( fun(Msg) -> @@ -1344,8 +1375,8 @@ user_queue_parse_query(User, Query) -> --record(roster, {uj, - user, +-record(roster, {usj, + us, jid, name = "", subscription = none, @@ -1359,11 +1390,14 @@ ask_to_pending(unsubscribe) -> none; ask_to_pending(Ask) -> Ask. -user_roster(User, Query, Lang, Admin) -> - LUser = jlib:nameprep(User), - Items1 = mnesia:dirty_index_read(roster, LUser, #roster.user), - Res = user_roster_parse_query(User, Items1, Query, Admin), - Items = mnesia:dirty_index_read(roster, LUser, #roster.user), +user_roster(SUser, Query, Lang, Admin) -> + UJID = jlib:string_to_jid(SUser), + User = UJID#jid.user, + Server = UJID#jid.server, + US = {UJID#jid.luser, UJID#jid.lserver}, + Items1 = mnesia:dirty_index_read(roster, US, #roster.us), + Res = user_roster_parse_query(User, Server, Items1, Query, Admin), + Items = mnesia:dirty_index_read(roster, US, #roster.us), SItems = lists:sort(Items), FItems = case SItems of @@ -1415,7 +1449,7 @@ user_roster(User, Query, Lang, Admin) -> "Remove")])]) end, SItems))])] end, - [?XC("h1", ?T("Roster of ") ++ User)] ++ + [?XC("h1", ?T("Roster of ") ++ us_to_list(US))] ++ case Res of ok -> [?CT("submitted"), ?P]; error -> [?CT("bad format"), ?P]; @@ -1428,7 +1462,7 @@ user_roster(User, Query, Lang, Admin) -> ?INPUTT("submit", "addjid", "Add JID") ])]. -user_roster_parse_query(User, Items, Query, Admin) -> +user_roster_parse_query(User, Server, Items, Query, Admin) -> case lists:keysearch("addjid", 1, Query) of {value, _} -> case lists:keysearch("newjid", 1, Query) of @@ -1437,7 +1471,7 @@ user_roster_parse_query(User, Items, Query, Admin) -> {value, {_, SJID}} -> case jlib:string_to_jid(SJID) of JID when is_record(JID, jid) -> - user_roster_subscribe_jid(User, JID), + user_roster_subscribe_jid(User, Server, JID), ok; error -> error @@ -1446,69 +1480,25 @@ user_roster_parse_query(User, Items, Query, Admin) -> error end; false -> - case lists:keysearch("adduser", 1, Query) of - {value, _} -> - case lists:keysearch("newuser", 1, Query) of - {value, {_, undefined}} -> - error; - {value, {_, U}} -> - if - Admin -> - user_roster_subscribe_users(User, U); - true -> - case jlib:make_jid(U, ?MYNAME, "") of - JID when is_record(JID, jid) -> - user_roster_subscribe_jid( - User, JID), - ok; - false -> - error - end - end; - false -> - error - end; - false -> - case catch user_roster_item_parse_query( - User, Items, Query) of - submitted -> - ok; - {'EXIT', _Reason} -> - error; - _ -> - nothing - end + case catch user_roster_item_parse_query( + User, Server, Items, Query) of + submitted -> + ok; + {'EXIT', _Reason} -> + error; + _ -> + nothing end end. -user_roster_subscribe_users(User1, User2) -> - case jlib:make_jid(User1, ?MYNAME, "") of - JID1 when is_record(JID1, jid) -> - case jlib:make_jid(User2, ?MYNAME, "") of - JID2 when is_record(JID2, jid) -> - mod_roster:out_subscription(User1, JID2, subscribe), - mod_roster:in_subscription(User2, JID1, subscribe), - mod_roster:out_subscription(User2, JID1, subscribe), - mod_roster:in_subscription(User1, JID2, subscribe), - mod_roster:out_subscription(User1, JID2, subscribed), - mod_roster:in_subscription(User2, JID1, subscribed), - mod_roster:out_subscription(User2, JID1, subscribed), - mod_roster:in_subscription(User1, JID2, subscribed), - ok; - false -> - error - end; - false -> - error - end. -user_roster_subscribe_jid(User, JID) -> - mod_roster:out_subscription(User, JID, subscribe), - UJID = jlib:make_jid(User, ?MYNAME, ""), +user_roster_subscribe_jid(User, Server, JID) -> + mod_roster:out_subscription(User, Server, JID, subscribe), + UJID = jlib:make_jid(User, Server, ""), ejabberd_router:route( UJID, JID, {xmlelement, "presence", [{"type", "subscribe"}], []}). -user_roster_item_parse_query(User, Items, Query) -> +user_roster_item_parse_query(User, Server, Items, Query) -> lists:foreach( fun(R) -> JID = R#roster.jid, @@ -1516,8 +1506,9 @@ user_roster_item_parse_query(User, Items, Query) -> "validate" ++ term_to_id(JID), 1, Query) of {value, _} -> JID1 = jlib:make_jid(JID), - mod_roster:out_subscription(User, JID1, subscribed), - UJID = jlib:make_jid(User, ?MYNAME, ""), + mod_roster:out_subscription( + User, Server, JID1, subscribed), + UJID = jlib:make_jid(User, Server, ""), ejabberd_router:route( UJID, JID1, {xmlelement, "presence", [{"type", "subscribed"}], []}), @@ -1526,7 +1517,7 @@ user_roster_item_parse_query(User, Items, Query) -> case lists:keysearch( "remove" ++ term_to_id(JID), 1, Query) of {value, _} -> - UJID = jlib:make_jid(User, ?MYNAME, ""), + UJID = jlib:make_jid(User, Server, ""), mod_roster:process_iq( UJID, UJID, #iq{type = set, @@ -2038,3 +2029,200 @@ pretty_print({xmlelement, Name, Attrs, Els}, Prefix) -> end end]. + +list_shared_roster_groups(Query, Lang) -> + Res = list_sr_groups_parse_query(Query), + SRGroups = mod_shared_roster:list_groups(?MYNAME), + 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")]) + ] + )] + )]), + [?XC("h1", ?T("Shared roster groups"))] ++ + case Res of + ok -> [?CT("submitted"), ?P]; + error -> [?CT("bad format"), ?P]; + nothing -> [] + end ++ + [?XAE("form", [{"method", "post"}], + [FGroups, + ?BR, + ?INPUTT("submit", "delete", "Delete Selected") + ]) + ]. + +list_sr_groups_parse_query(Query) -> + case lists:keysearch("addnew", 1, Query) of + {value, _} -> + list_sr_groups_parse_addnew(Query); + _ -> + case lists:keysearch("delete", 1, Query) of + {value, _} -> + list_sr_groups_parse_delete(Query); + _ -> + nothing + end + end. + +list_sr_groups_parse_addnew(Query) -> + case lists:keysearch("namenew", 1, Query) of + {value, {_, Group}} when Group /= "" -> + mod_shared_roster:create_group(?MYNAME, Group), + ok; + _ -> + error + end. + +list_sr_groups_parse_delete(Query) -> + SRGroups = mod_shared_roster:list_groups(?MYNAME), + lists:foreach( + fun(Group) -> + case lists:member({"selected", Group}, Query) of + true -> + mod_shared_roster:delete_group(?MYNAME, Group); + _ -> + ok + end + end, SRGroups), + ok. + + +shared_roster_group(Group, Query, Lang) -> + Res = shared_roster_group_parse_query(?MYNAME, Group, Query), + GroupOpts = mod_shared_roster:get_group_opts(?MYNAME, Group), + Name = get_opt(GroupOpts, name, ""), + Description = get_opt(GroupOpts, description, ""), + Members = mod_shared_roster:get_group_users(?MYNAME, Group), + Disabled = false, + DisplayedGroups = get_opt(GroupOpts, displayed_groups, []), + FMembers = [[us_to_list(Member), $\n] || Member <- Members], + FDisplayedGroups = [[DG, $\n] || DG <- DisplayedGroups], + FGroup = + ?XAE("table", [], + [?XE("tbody", + [?XE("tr", + [?XCT("td", "Name:"), + ?XE("td", [?INPUT("text", "name", Name)]) + ] + ), + ?XE("tr", + [?XCT("td", "Description:"), + ?XE("td", [?XAC("textarea", [{"name", "description"}, + {"rows", "3"}, + {"cols", "20"}], + Description)]) + ] + ), + ?XE("tr", + [?XCT("td", "Members:"), + ?XE("td", [?XAC("textarea", [{"name", "members"}, + {"rows", "3"}, + {"cols", "20"}], + FMembers)]) + ] + ), + ?XE("tr", + [?XCT("td", "Displayed Groups:"), + ?XE("td", [?XAC("textarea", [{"name", "dispgroups"}, + {"rows", "3"}, + {"cols", "20"}], + FDisplayedGroups)]) + ] + )] + )]), + [?XC("h1", ?T("Shared roster group " ++ Group))] ++ + case Res of + ok -> [?CT("submitted"), ?P]; + error -> [?CT("bad format"), ?P]; + nothing -> [] + end ++ + [?XAE("form", [{"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, + mod_shared_roster:set_group_opts( + ?MYNAME, Group, NameOpt ++ DispGroupsOpt ++ DescriptionOpt), + + OldMembers = mod_shared_roster:get_group_users(?MYNAME, Group), + NewMembers = + lists:foldl( + fun(_SJID, error) -> error; + (SJID, 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, [], string:tokens(SMembers, "\r\n")), + if + NewMembers == error -> error; + true -> + AddedMembers = NewMembers -- OldMembers, + RemovedMembers = OldMembers -- NewMembers, + lists:foreach( + fun(US) -> + mod_shared_roster:remove_user_from_group( + Host, US, Group) + end, RemovedMembers), + lists:foreach( + fun(US) -> + mod_shared_roster: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 + end. + |