📄 ejabberd_web_admin.erl
字号:
end); _ -> ok end end, AccessRules), ok.access_rule_to_xhtml(Rules) -> Text = lists:flatmap( fun({Access, ACL} = Rule) -> SAccess = atom_to_list(Access), SACL = atom_to_list(ACL), SAccess ++ "\t" ++ SACL ++ "\n" end, Rules), ?XAC("textarea", [{"name", "rules"}, {"rows", "16"}, {"cols", "80"}], Text).parse_access_rule(Text) -> Strings = string:tokens(Text, "\r\n"), case catch lists:flatmap( fun(String) -> case string:tokens(String, "\s\t") of [Access, ACL] -> [{list_to_atom(Access), list_to_atom(ACL)}]; [] -> [] end end, Strings) of {'EXIT', _Reason} -> error; Rs -> {ok, Rs} end.list_users(Query, Lang) -> Res = list_users_parse_query(Query), Users = ejabberd_auth:dirty_get_registered_users(), SUsers = lists:sort(Users), FUsers = case length(SUsers) of N when N =< 100 -> [list_given_users(SUsers, "../", Lang)]; N -> NParts = trunc(math:sqrt(N * 0.618)) + 1, M = trunc(N / NParts) + 1, lists:flatmap( 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) end, Name = lists:nth(K, SUsers) ++ [$\s, 226, 128, 148, $\s] ++ Last, [?AC(Node ++ "/", Name), ?BR] end, lists:seq(1, N, M)) end, case Res of ok -> [?CT("submitted"), ?P]; error -> [?CT("bad format"), ?P]; nothing -> [] end ++ [?XAE("form", [{"method", "post"}], [?XE("table", [?XE("tr", [?XC("td", ?T("User") ++ ":"), ?XE("td", [?INPUT("text", "newusername", "")]) ]), ?XE("tr", [?XC("td", ?T("Password") ++ ":"), ?XE("td", [?INPUT("password", "newuserpassword", "")]) ]), ?XE("tr", [?X("td"), ?XAE("td", [{"class", "alignright"}], [?INPUTT("submit", "addnewuser", "Add User")]) ])]), ?P] ++ FUsers)].list_users_parse_query(Query) -> case lists:keysearch("addnewuser", 1, Query) of {value, _} -> {value, {_, User}} = lists:keysearch("newusername", 1, Query), {value, {_, Password}} = lists:keysearch("newuserpassword", 1, Query), case jlib:nodeprep(User) of error -> error; "" -> error; _ -> ejabberd_auth:try_register(User, Password), ok end; false -> nothing end.list_users_in_diapason(Diap, Lang) -> Users = ejabberd_auth:dirty_get_registered_users(), SUsers = lists:sort(Users), {ok, [S1, S2]} = regexp:split(Diap, "-"), N1 = list_to_integer(S1), N2 = list_to_integer(S2), Sub = lists:sublist(SUsers, N1, N2 - N1 + 1), [list_given_users(Sub, "../../", Lang)].list_given_users(Users, Prefix, Lang) -> ?XE("table", [?XE("thead", [?XE("tr", [?XCT("td", "User"), ?XCT("td", "Offline messages"), ?XCT("td", "Last Activity")])]), ?XE("tbody", lists:map( fun(User) -> QueueLen = length(mnesia:dirty_read({offline_msg, User})), FQueueLen = [?AC(Prefix ++ "user/" ++ User ++ "/queue/", integer_to_list(QueueLen))], FLast = case ejabberd_sm:get_user_resources(User) of [] -> case mnesia:dirty_read({last_activity, User}) of [] -> ?T("Never"); [E] -> Shift = element(3, E), TimeStamp = {Shift div 1000000, Shift rem 1000000, 0}, {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:now_to_local_time(TimeStamp), lists:flatten( io_lib:format( "~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", [Year, Month, Day, Hour, Minute, Second])) end; _ -> ?T("Online") end, ?XE("tr", [?XE("td", [?AC(Prefix ++ "user/" ++ User ++ "/", User)]), ?XE("td", FQueueLen), ?XC("td", FLast)]) end, Users) )]).get_stats(Lang) -> OnlineUsers = mnesia:table_info(presence, size), AuthUsers = mnesia:table_info(session, size), RegisteredUsers = mnesia:table_info(passwd, size), S2SConns = ejabberd_s2s:dirty_get_connections(), S2SConnections = length(S2SConns), S2SServers = length(lists:usort([element(2, C) || C <- S2SConns])), [?XAE("table", [], [?XE("tbody", [?XE("tr", [?XCT("td", "Registered users"), ?XC("td", integer_to_list(RegisteredUsers))]), ?XE("tr", [?XCT("td", "Authentificated users"), ?XC("td", integer_to_list(AuthUsers))]), ?XE("tr", [?XCT("td", "Online users"), ?XC("td", integer_to_list(OnlineUsers))]), ?XE("tr", [?XCT("td", "Outgoing S2S connections"), ?XC("td", integer_to_list(S2SConnections))]), ?XE("tr", [?XCT("td", "Outgoing S2S servers"), ?XC("td", integer_to_list(S2SServers))]) ]) ])].list_online_users(_Lang) -> Users = lists:map(fun({U, R}) -> U end, ejabberd_sm:dirty_get_sessions_list()), SUsers = lists:usort(Users), lists:flatmap( fun(U) -> [?AC("../user/" ++ U ++ "/", U), ?BR] end, SUsers).user_info(User, Query, Lang) -> Res = user_parse_query(User, Query), Resources = ejabberd_sm:get_user_resources(User), FResources = case Resources of [] -> [?CT("None")]; _ -> [?XE("ul", lists:map(fun(R) -> ?LI([?C(R)]) end, lists:sort(Resources)))] end, Password = ejabberd_auth:get_password_s(User), FPassword = [?INPUT("text", "password", Password), ?C(" "), ?INPUTT("submit", "chpassword", "Change Password")], QueueLen = length(mnesia:dirty_read({offline_msg, User})), FQueueLen = [?AC("queue/", integer_to_list(QueueLen))], [?XC("h1", ?T("User ") ++ User)] ++ case Res of ok -> [?CT("submitted"), ?P]; error -> [?CT("bad format"), ?P]; nothing -> [] end ++ [?XAE("form", [{"method", "post"}], [?XCT("h3", "Connected Resources:")] ++ FResources ++ [?XCT("h3", "Password:")] ++ FPassword ++ [?XCT("h3", "Offline messages:")] ++ FQueueLen ++ [?XE("h3", [?ACT("roster/", "Roster")])] ++ [?BR, ?INPUTT("submit", "removeuser", "Remove User")])].user_parse_query(User, 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), ok; _ -> error end; _ -> case lists:keysearch("removeuser", 1, Query) of {value, _} -> ejabberd_auth:remove_user(User), ok; false -> nothing end end.user_queue(User, Query, Lang) -> Res = user_queue_parse_query(User, Query), Msgs = lists:keysort(3, mnesia:dirty_read({offline_msg, User})), FMsgs = lists:map( fun({offline_msg, _User, 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}} = calendar:now_to_local_time(TimeStamp), Time = lists:flatten( io_lib:format( "~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", [Year, Month, Day, Hour, Minute, Second])), SFrom = jlib:jid_to_string(From), STo = jlib:jid_to_string(To), Attrs2 = jlib:replace_from_to_attrs(SFrom, STo, Attrs), Packet = jlib:remove_attr( "jeai-id", {xmlelement, Name, Attrs2, Els}), FPacket = pretty_print(Packet), ?XE("tr", [?XAE("td", [{"class", "valign"}], [?INPUT("checkbox", "selected", ID)]), ?XAC("td", [{"class", "valign"}], Time), ?XAC("td", [{"class", "valign"}], SFrom), ?XAC("td", [{"class", "valign"}], STo), ?XAE("td", [{"class", "valign"}], [?XC("pre", FPacket)])] ) end, Msgs), [?XC("h1", io_lib:format(?T("~s offline messages queue"), [User]))] ++ case Res of ok -> [?CT("submitted"), ?P]; error -> [?CT("bad format"), ?P]; nothing -> [] end ++ [?XAE("form", [{"method", "post"}], [?XE("table", [?XE("thead", [?XE("tr", [?X("td"), ?XCT("td", "Time"), ?XCT("td", "From"), ?XCT("td", "To"), ?XCT("td", "Packet") ])]), ?XE("tbody", FMsgs)]), ?BR, ?INPUTT("submit", "delete", "Delete Selected") ])].user_queue_parse_query(User, Query) -> case lists:keysearch("delete", 1, Query) of {value, _} -> Msgs = lists:keysort(3, mnesia:dirty_read({offline_msg, User})), F = fun() -> lists:foreach( fun(Msg) -> ID = jlib:encode_base64( binary_to_list(term_to_binary(Msg))), case lists:member({"selected", ID}, Query) of true -> mnesia:delete_object(Msg); false -> ok end end, Msgs) end, mnesia:transaction(F), ok; false -> nothing end.-record(roster, {uj, user, jid, name = "", subscription = none, ask = none, groups = [], xattrs = [], xs = []}).ask_to_pending(subscribe) -> out;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), SItems = lists:sort(Items), FItems = case SItems of [] -> [?CT("None")]; _ -> [?XE("table", [?XE("thead", [?XE("tr", [?XCT("td", "JID"), ?XCT("td", "Nickname"), ?XCT("td", "Subscription"), ?XCT("td", "Pending"), ?XCT("td", "Groups") ])]), ?XE("tbody", lists:map( fun(R) -> Groups = lists:flatmap( fun(Group) -> [?C(Group), ?BR] end, R#roster.groups), Pending = ask_to_pending(R#roster.ask), ?XE("tr", [?XAC("td", [{"class", "valign"}], jlib:jid_to_string(R#roster.jid)), ?XAC("td", [{"class", "valign"}], R#roster.name), ?XAC("td", [{"class", "valign"}], atom_to_list(R#roster.subscription)), ?XAC("td", [{"class", "valign"}], atom_to_list(Pending)), ?XAE("td", [{"class", "valign"}], Groups), if Pending == in -> ?XAE("td", [{"class", "valign"}], [?INPUTT("submit", "validate" ++ term_to_id(R#roster.jid), "Validate")]); true -> ?X("td") end, ?XAE("td", [{"class", "valign"}], [?INPUTT("submit", "remove" ++ term_to_id(R#roster.jid), "Remove")])]) end, SItems))])] end, [?XC("h1", ?T("Roster of ") ++ User)] ++ case Res of ok -> [?CT("submitted"), ?P]; error -> [?CT("bad format"), ?P]; nothing -> [] end ++ [?XAE("form", [{"method", "post"}], FItems ++ [?P, ?INPUT("text", "newjid", ""), ?C(" "), ?INPUTT("submit", "addjid", "Add JID") ])].user_roster_parse_query(User, Items, Query, Admin) -> case lists:keysearch("addjid", 1, Query) of {value, _} -> case lists:keysearch("newjid", 1, Query) of {value, {_, undefined}} -> error; {value, {_, SJID}} -> case jlib:string_to_jid(SJID) of JID when is_record(JID, jid) -> user_roster_subscribe_jid(User, JID), ok; error -> error end; false -> 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 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, ""), ejabberd_router:route( UJID, JID, {xmlelement, "presence", [{"type", "subscribe"}], []}).user_roster_item_parse_query(User, Items, Query) -> lists:foreach( fun(R) -> JID = R#roster.jid, case lists:keysearch( "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, ""), ejabberd_router:route( UJID, JID1, {xmlelement, "presence", [{"type", "subscribed"}], []}), throw(submitted); false -> case lists:keysearch( "remove" ++ term_to_id(JID), 1, Query) of {value, _} -> UJID = jlib:make_jid(User, ?MYNAME, ""), mod_roster:process_iq( UJID, UJID, #iq{type = set, sub_el = {xmlelement, "query",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -