diff options
Diffstat (limited to 'src/mod_muc_admin.erl')
-rw-r--r-- | src/mod_muc_admin.erl | 207 |
1 files changed, 118 insertions, 89 deletions
diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index 11f96b9bd..7c6e84c45 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -11,48 +11,39 @@ -behaviour(gen_mod). --export([ - start/2, stop/1, % gen_mod API - muc_online_rooms/1, - muc_unregister_nick/1, - create_room/3, destroy_room/3, +-export([start/2, stop/1, muc_online_rooms/1, + muc_unregister_nick/1, create_room/3, destroy_room/2, create_rooms_file/1, destroy_rooms_file/1, rooms_unused_list/2, rooms_unused_destroy/2, - get_user_rooms/2, - get_room_occupants/2, - get_room_occupants_number/2, - send_direct_invitation/4, - change_room_option/4, - set_room_affiliation/4, - get_room_affiliations/2, - web_menu_main/2, web_page_main/2, % Web Admin API - web_menu_host/3, web_page_host/3 - ]). + get_user_rooms/2, get_room_occupants/2, + get_room_occupants_number/2, send_direct_invitation/5, + change_room_option/4, get_room_options/2, + set_room_affiliation/4, get_room_affiliations/2, + web_menu_main/2, web_page_main/2, web_menu_host/3, + web_page_host/3, mod_opt_type/1, get_commands_spec/0]). -include("ejabberd.hrl"). -include("logger.hrl"). -include("jlib.hrl"). -include("mod_muc_room.hrl"). +-include("mod_muc.hrl"). -include("ejabberd_http.hrl"). -include("ejabberd_web_admin.hrl"). -include("ejabberd_commands.hrl"). -%% Copied from mod_muc/mod_muc.erl --record(muc_online_room, {name_host, pid}). - %%---------------------------- %% gen_mod %%---------------------------- start(Host, _Opts) -> - ejabberd_commands:register_commands(commands()), + ejabberd_commands:register_commands(get_commands_spec()), ejabberd_hooks:add(webadmin_menu_main, ?MODULE, web_menu_main, 50), ejabberd_hooks:add(webadmin_menu_host, Host, ?MODULE, web_menu_host, 50), ejabberd_hooks:add(webadmin_page_main, ?MODULE, web_page_main, 50), ejabberd_hooks:add(webadmin_page_host, Host, ?MODULE, web_page_host, 50). stop(Host) -> - ejabberd_commands:unregister_commands(commands()), + ejabberd_commands:unregister_commands(get_commands_spec()), ejabberd_hooks:delete(webadmin_menu_main, ?MODULE, web_menu_main, 50), ejabberd_hooks:delete(webadmin_menu_host, Host, ?MODULE, web_menu_host, 50), ejabberd_hooks:delete(webadmin_page_main, ?MODULE, web_page_main, 50), @@ -62,10 +53,11 @@ stop(Host) -> %%% Register commands %%% -commands() -> +get_commands_spec() -> [ #ejabberd_commands{name = muc_online_rooms, tags = [muc], desc = "List existing rooms ('global' to get all vhosts)", + policy = admin, module = ?MODULE, function = muc_online_rooms, args = [{host, binary}], result = {rooms, {list, {room, string}}}}, @@ -84,16 +76,17 @@ commands() -> #ejabberd_commands{name = destroy_room, tags = [muc_room], desc = "Destroy a MUC room", module = ?MODULE, function = destroy_room, - args = [{name, binary}, {service, binary}, - {host, binary}], + args = [{name, binary}, {service, binary}], result = {res, rescode}}, #ejabberd_commands{name = create_rooms_file, tags = [muc], desc = "Create the rooms indicated in file", + longdesc = "Provide one room JID per line. Rooms will be created after restart.", module = ?MODULE, function = create_rooms_file, args = [{file, string}], result = {res, rescode}}, #ejabberd_commands{name = destroy_rooms_file, tags = [muc], desc = "Destroy the rooms indicated in file", + longdesc = "Provide one room JID per line.", module = ?MODULE, function = destroy_rooms_file, args = [{file, string}], result = {res, rescode}}, @@ -136,7 +129,7 @@ commands() -> desc = "Send a direct invitation to several destinations", longdesc = "Password and Message can also be: none. Users JIDs are separated with : ", module = ?MODULE, function = send_direct_invitation, - args = [{room, binary}, {password, binary}, {reason, binary}, {users, binary}], + args = [{name, binary}, {service, binary}, {password, binary}, {reason, binary}, {users, binary}], result = {res, rescode}}, #ejabberd_commands{name = change_room_option, tags = [muc_room], @@ -145,6 +138,16 @@ commands() -> args = [{name, binary}, {service, binary}, {option, binary}, {value, binary}], result = {res, rescode}}, + #ejabberd_commands{name = get_room_options, tags = [muc_room], + desc = "Get options from a MUC room", + module = ?MODULE, function = get_room_options, + args = [{name, binary}, {service, binary}], + result = {options, {list, + {option, {tuple, + [{name, string}, + {value, string} + ]}} + }}}, #ejabberd_commands{name = set_room_affiliation, tags = [muc_room], desc = "Change an affiliation in a MUC room", @@ -175,7 +178,8 @@ muc_online_rooms(ServerHost) -> MUCHost = find_host(ServerHost), Rooms = ets:tab2list(muc_online_room), lists:foldl( - fun({_, {Roomname, Host}, _}, Results) -> + fun(Room, Results) -> + {Roomname, Host} = Room#muc_online_room.name_host, case MUCHost of global -> [<<Roomname/binary, "@", Host/binary>> | Results]; @@ -238,8 +242,8 @@ web_menu_host(Acc, _Host, Lang) -> ])). web_page_main(_, #request{path=[<<"muc">>], lang = Lang} = _Request) -> - Res = [?XC(<<"h1">>, <<"Multi-User Chat">>), - ?XC(<<"h3">>, <<"Statistics">>), + Res = [?XCT(<<"h1">>, <<"Multi-User Chat">>), + ?XCT(<<"h3">>, <<"Statistics">>), ?XAE(<<"table">>, [], [?XE(<<"tbody">>, [?TDTD(<<"Total rooms">>, ets:info(muc_online_room, size)), ?TDTD(<<"Permanent rooms">>, mnesia:table_info(muc_room, size)), @@ -276,7 +280,7 @@ get_sort_query(Q) -> get_sort_query2(Q) -> {value, {_, String}} = lists:keysearch(<<"sort">>, 1, Q), - Integer = list_to_integer(binary_to_list(String)), + Integer = jlib:binary_to_integer(String), case Integer >= 0 of true -> {ok, {normal, Integer}}; false -> {ok, {reverse, abs(Integer)}} @@ -298,22 +302,22 @@ make_rooms_page(Host, Lang, {Sort_direction, Sort_column}) -> <<"Persistent">>, <<"Logging">>, <<"Just created">>, - <<"Title">>], + <<"Room title">>], {Titles_TR, _} = lists:mapfoldl( fun(Title, Num_column) -> NCS = jlib:integer_to_binary(Num_column), TD = ?XE(<<"td">>, [?CT(Title), ?C(<<" ">>), - ?ACT(<<"?sort=", NCS/binary>>, <<"<">>), + ?AC(<<"?sort=", NCS/binary>>, <<"<">>), ?C(<<" ">>), - ?ACT(<<"?sort=-", NCS/binary>>, <<">">>)]), + ?AC(<<"?sort=-", NCS/binary>>, <<">">>)]), {TD, Num_column+1} end, 1, Titles), - [?XC(<<"h1">>, <<"Multi-User Chat">>), - ?XC(<<"h2">>, <<"Rooms">>), + [?XCT(<<"h1">>, <<"Multi-User Chat">>), + ?XCT(<<"h2">>, <<"Chatrooms">>), ?XE(<<"table">>, [?XE(<<"thead">>, [?XE(<<"tr">>, Titles_TR)] @@ -352,7 +356,7 @@ build_info_room({Name, Host, Pid}) -> false -> Last_message1 = queue:last(History), {_, _, _, Ts_last, _} = Last_message1, - jlib:timestamp_to_iso(Ts_last) + jlib:timestamp_to_legacy(Ts_last) end, {<<Name/binary, "@", Host/binary>>, @@ -392,7 +396,9 @@ prepare_room_info(Room_info) -> %% @spec (Name::binary(), Host::binary(), ServerHost::binary()) -> %% ok | error %% @doc Create a room immediately with the default options. -create_room(Name, Host, ServerHost) -> +create_room(Name1, Host1, ServerHost) -> + Name = jid:nodeprep(Name1), + Host = jid:nodeprep(Host1), %% Get the default room options from the muc configuration DefRoomOpts = gen_mod:get_module_opt(ServerHost, mod_muc, @@ -406,7 +412,6 @@ create_room(Name, Host, ServerHost) -> AcCreate = gen_mod:get_module_opt(ServerHost, mod_muc, access_create, fun(X) -> X end, all), AcAdmin = gen_mod:get_module_opt(ServerHost, mod_muc, access_admin, fun(X) -> X end, none), AcPer = gen_mod:get_module_opt(ServerHost, mod_muc, access_persistent, fun(X) -> X end, all), - _PersistHistory = gen_mod:get_module_opt(ServerHost, mod_muc, persist_history, fun(X) -> X end, false), HistorySize = gen_mod:get_module_opt(ServerHost, mod_muc, history_size, fun(X) -> X end, 20), RoomShaper = gen_mod:get_module_opt(ServerHost, mod_muc, room_shaper, fun(X) -> X end, none), @@ -441,12 +446,12 @@ muc_create_room(ServerHost, {Name, Host, _}, DefRoomOpts) -> io:format("Creating room ~s@~s~n", [Name, Host]), mod_muc:store_room(ServerHost, Host, Name, DefRoomOpts). -%% @spec (Name::binary(), Host::binary(), ServerHost::binary()) -> +%% @spec (Name::binary(), Host::binary()) -> %% ok | {error, room_not_exists} %% @doc Destroy the room immediately. %% If the room has participants, they are not notified that the room was destroyed; %% they will notice when they try to chat and receive an error that the room doesn't exist. -destroy_room(Name, Service, _Server) -> +destroy_room(Name, Service) -> case mnesia:dirty_read(muc_online_room, {Name, Service}) of [R] -> Pid = R#muc_online_room.pid, @@ -458,7 +463,7 @@ destroy_room(Name, Service, _Server) -> destroy_room({N, H, SH}) -> io:format("Destroying room: ~s@~s - vhost: ~s~n", [N, H, SH]), - destroy_room(N, H, SH). + destroy_room(N, H). %%---------------------------- @@ -469,7 +474,7 @@ destroy_room({N, H, SH}) -> %% The file encoding must be UTF-8 destroy_rooms_file(Filename) -> - {ok, F} = file:open(Filename, [read]), + {ok, F} = file:open(Filename, [read, binary]), RJID = read_room(F), Rooms = read_rooms(F, RJID, []), file:close(F), @@ -497,23 +502,16 @@ read_room(F) -> %% This function is quite rudimentary %% and may not be accurate split_roomjid(RoomJID) -> - [Name, Host] = string:tokens(RoomJID, "@"), - [_MUC_service_name | ServerHostList] = string:tokens(Host, "."), - ServerHost = join(ServerHostList, "."), + [Name, Host] = binary:split(RoomJID, <<"@">>), + [_MUC_service_name, ServerHost] = binary:split(Host, <<".">>), {Name, Host, ServerHost}. -%% This function is copied from string:join/2 in Erlang/OTP R12B-1 -%% Note that string:join/2 is not implemented in Erlang/OTP R11B -join([H|T], Sep) -> - H ++ lists:concat([Sep ++ X || X <- T]). - - %%---------------------------- %% Create Rooms in File %%---------------------------- create_rooms_file(Filename) -> - {ok, F} = file:open(Filename, [read]), + {ok, F} = file:open(Filename, [read, binary]), RJID = read_room(F), Rooms = read_rooms(F, RJID, []), file:close(F), @@ -604,7 +602,7 @@ decide_room({_Room_name, _Host, Room_pid}, Last_allowed) -> Num_users = length(?DICT:to_list(Room_users)), History = (S#state.history)#lqueue.queue, - Ts_now = calendar:now_to_universal_time(now()), + Ts_now = calendar:universal_time(), Ts_uptime = uptime_seconds(), {Has_hist, Last} = case queue:is_empty(History) of true -> @@ -672,7 +670,7 @@ get_room_occupants(Pid) -> S = get_room_state(Pid), lists:map( fun({_LJID, Info}) -> - {jlib:jid_to_string(Info#user.jid), + {jid:to_string(Info#user.jid), Info#user.nick, atom_to_list(Info#user.role)} end, @@ -686,32 +684,36 @@ get_room_occupants_number(Room, Host) -> %%---------------------------- %% http://xmpp.org/extensions/xep-0249.html -send_direct_invitation(RoomString, Password, Reason, UsersString) -> - RoomJid = jlib:string_to_jid(RoomString), +send_direct_invitation(RoomName, RoomService, Password, Reason, UsersString) -> + RoomJid = jid:make(RoomName, RoomService, <<"">>), + RoomString = jid:to_string(RoomJid), XmlEl = build_invitation(Password, Reason, RoomString), - UsersStrings = get_users_to_invite(RoomJid, binary_to_list(UsersString)), - [send_direct_invitation(RoomJid, jlib:string_to_jid(list_to_binary(UserStrings)), XmlEl) + UsersStrings = get_users_to_invite(RoomJid, UsersString), + [send_direct_invitation(RoomJid, UserStrings, XmlEl) || UserStrings <- UsersStrings], timer:sleep(1000), ok. get_users_to_invite(RoomJid, UsersString) -> - UsersStrings = string:tokens(UsersString, ":"), + UsersStrings = binary:split(UsersString, <<":">>, [global]), OccupantsTuples = get_room_occupants(RoomJid#jid.luser, RoomJid#jid.lserver), - OccupantsJids = [jlib:string_to_jid(JidString) + OccupantsJids = [jid:from_string(JidString) || {JidString, _Nick, _} <- OccupantsTuples], - lists:filter( - fun(UserString) -> - UserJid = jlib:string_to_jid(list_to_binary(UserString)), - %% [{"badlop@localhost/work","badlop","moderator"}] - lists:all(fun(OccupantJid) -> - UserJid#jid.luser /= OccupantJid#jid.luser - orelse UserJid#jid.lserver /= OccupantJid#jid.lserver - end, - OccupantsJids) - end, - UsersStrings). + lists:filtermap( + fun(UserString) -> + UserJid = jid:from_string(UserString), + Val = lists:all(fun(OccupantJid) -> + UserJid#jid.luser /= OccupantJid#jid.luser + orelse UserJid#jid.lserver /= OccupantJid#jid.lserver + end, + OccupantsJids), + case Val of + true -> {true, UserJid}; + _ -> false + end + end, + UsersStrings). build_invitation(Password, Reason, RoomString) -> PasswordAttrList = case Password of @@ -782,10 +784,17 @@ change_option(Option, Value, Config) -> case Option of allow_change_subj -> Config#config{allow_change_subj = Value}; allow_private_messages -> Config#config{allow_private_messages = Value}; + allow_private_messages_from_visitors -> Config#config{allow_private_messages_from_visitors = Value}; allow_query_users -> Config#config{allow_query_users = Value}; allow_user_invites -> Config#config{allow_user_invites = Value}; + allow_visitor_nickchange -> Config#config{allow_visitor_nickchange = Value}; + allow_visitor_status -> Config#config{allow_visitor_status = Value}; + allow_voice_requests -> Config#config{allow_voice_requests = Value}; anonymous -> Config#config{anonymous = Value}; + captcha_protected -> Config#config{captcha_protected = Value}; + description -> Config#config{description = Value}; logging -> Config#config{logging = Value}; + mam -> Config#config{mam = Value}; max_users -> Config#config{max_users = Value}; members_by_default -> Config#config{members_by_default = Value}; members_only -> Config#config{members_only = Value}; @@ -795,9 +804,29 @@ change_option(Option, Value, Config) -> persistent -> Config#config{persistent = Value}; public -> Config#config{public = Value}; public_list -> Config#config{public_list = Value}; - title -> Config#config{title = Value} + title -> Config#config{title = Value}; + vcard -> Config#config{vcard = Value}; + voice_request_min_interval -> Config#config{voice_request_min_interval = Value} + end. + +%%---------------------------- +%% Get Room Options +%%---------------------------- + +get_room_options(Name, Service) -> + case get_room_pid(Name, Service) of + room_not_found -> []; + Pid -> get_room_options(Pid) end. +get_room_options(Pid) -> + Config = get_room_config(Pid), + get_options(Config). + +get_options(Config) -> + Fields = record_info(fields, config), + [config | Values] = tuple_to_list(Config), + lists:zip(Fields, Values). %%---------------------------- %% Get Room Affiliations @@ -841,34 +870,32 @@ set_room_affiliation(Name, Service, JID, AffiliationString) -> [R] -> %% Get the PID for the online room so we can get the state of the room Pid = R#muc_online_room.pid, - {ok, StateData} = gen_fsm:sync_send_all_state_event(Pid, {process_item_change, {jlib:string_to_jid(JID), affiliation, Affiliation, <<"">>}, <<"">>}), + {ok, StateData} = gen_fsm:sync_send_all_state_event(Pid, {process_item_change, {jid:from_string(JID), affiliation, Affiliation, <<"">>}, <<"">>}), mod_muc:store_room(StateData#state.server_host, StateData#state.host, StateData#state.room, make_opts(StateData)), ok; [] -> error end. --define(MAKE_CONFIG_OPT(Opt), {Opt, Config#config.Opt}). - make_opts(StateData) -> Config = StateData#state.config, [ - ?MAKE_CONFIG_OPT(title), - ?MAKE_CONFIG_OPT(allow_change_subj), - ?MAKE_CONFIG_OPT(allow_query_users), - ?MAKE_CONFIG_OPT(allow_private_messages), - ?MAKE_CONFIG_OPT(public), - ?MAKE_CONFIG_OPT(public_list), - ?MAKE_CONFIG_OPT(persistent), - ?MAKE_CONFIG_OPT(moderated), - ?MAKE_CONFIG_OPT(members_by_default), - ?MAKE_CONFIG_OPT(members_only), - ?MAKE_CONFIG_OPT(allow_user_invites), - ?MAKE_CONFIG_OPT(password_protected), - ?MAKE_CONFIG_OPT(password), - ?MAKE_CONFIG_OPT(anonymous), - ?MAKE_CONFIG_OPT(logging), - ?MAKE_CONFIG_OPT(max_users), + {title, Config#config.title}, + {allow_change_subj, Config#config.allow_change_subj}, + {allow_query_users, Config#config.allow_query_users}, + {allow_private_messages, Config#config.allow_private_messages}, + {public, Config#config.public}, + {public_list, Config#config.public_list}, + {persistent, Config#config.persistent}, + {moderated, Config#config.moderated}, + {members_by_default, Config#config.members_by_default}, + {members_only, Config#config.members_only}, + {allow_user_invites, Config#config.allow_user_invites}, + {password_protected, Config#config.password_protected}, + {password, Config#config.password}, + {anonymous, Config#config.anonymous}, + {logging, Config#config.logging}, + {max_users, Config#config.max_users}, {affiliations, ?DICT:to_list(StateData#state.affiliations)}, {subject, StateData#state.subject}, {subject_author, StateData#state.subject_author} @@ -892,3 +919,5 @@ find_host(ServerHost) when is_list(ServerHost) -> find_host(list_to_binary(ServerHost)); find_host(ServerHost) -> gen_mod:get_module_opt_host(ServerHost, mod_muc, <<"conference.@HOST@">>). + +mod_opt_type(_) -> []. |