aboutsummaryrefslogtreecommitdiff
path: root/src/mod_muc_admin.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_muc_admin.erl')
-rw-r--r--src/mod_muc_admin.erl207
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(_) -> [].