Implement database backend interface for MUC, BOSH and auth_anonyous
This commit is contained in:
parent
31491ebe16
commit
0baaad30b1
|
@ -0,0 +1,6 @@
|
||||||
|
-type local_hint() :: undefined | integer() | {apply, atom(), atom()}.
|
||||||
|
|
||||||
|
-record(route, {domain :: binary(),
|
||||||
|
server_host :: binary(),
|
||||||
|
pid :: undefined | pid(),
|
||||||
|
local_hint :: local_hint()}).
|
|
@ -23,11 +23,15 @@
|
||||||
{'_', binary()},
|
{'_', binary()},
|
||||||
opts = [] :: list() | '_'}).
|
opts = [] :: list() | '_'}).
|
||||||
|
|
||||||
-record(muc_online_room,
|
|
||||||
{name_host = {<<"">>, <<"">>} :: {binary(), binary()} | '$1' |
|
|
||||||
{'_', binary()} | '_',
|
|
||||||
pid = self() :: pid() | '$2' | '_' | '$1'}).
|
|
||||||
|
|
||||||
-record(muc_registered,
|
-record(muc_registered,
|
||||||
{us_host = {{<<"">>, <<"">>}, <<"">>} :: {{binary(), binary()}, binary()} | '$1',
|
{us_host = {{<<"">>, <<"">>}, <<"">>} :: {{binary(), binary()}, binary()} | '$1',
|
||||||
nick = <<"">> :: binary()}).
|
nick = <<"">> :: binary()}).
|
||||||
|
|
||||||
|
-record(muc_online_room,
|
||||||
|
{name_host :: {binary(), binary()} | '$1' | {'_', binary()} | '_',
|
||||||
|
pid :: pid() | '$2' | '_' | '$1'}).
|
||||||
|
|
||||||
|
-record(muc_online_users, {us :: {binary(), binary()},
|
||||||
|
resource :: binary() | '_',
|
||||||
|
room :: binary() | '_' | '$1',
|
||||||
|
host :: binary() | '_' | '$2'}).
|
||||||
|
|
|
@ -120,10 +120,3 @@
|
||||||
room_shaper = none :: shaper:shaper(),
|
room_shaper = none :: shaper:shaper(),
|
||||||
room_queue = queue:new() :: ?TQUEUE
|
room_queue = queue:new() :: ?TQUEUE
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-record(muc_online_users, {us = {<<>>, <<>>} :: {binary(), binary()},
|
|
||||||
resource = <<>> :: binary() | '_',
|
|
||||||
room = <<>> :: binary() | '_' | '$1',
|
|
||||||
host = <<>> :: binary() | '_' | '$2'}).
|
|
||||||
|
|
||||||
-type muc_online_users() :: #muc_online_users{}.
|
|
||||||
|
|
|
@ -343,7 +343,7 @@ send_service_message_all_mucs(Subject, AnnouncementText) ->
|
||||||
fun(ServerHost) ->
|
fun(ServerHost) ->
|
||||||
MUCHost = gen_mod:get_module_opt_host(
|
MUCHost = gen_mod:get_module_opt_host(
|
||||||
ServerHost, mod_muc, <<"conference.@HOST@">>),
|
ServerHost, mod_muc, <<"conference.@HOST@">>),
|
||||||
mod_muc:broadcast_service_message(MUCHost, Message)
|
mod_muc:broadcast_service_message(ServerHost, MUCHost, Message)
|
||||||
end,
|
end,
|
||||||
?MYHOSTS).
|
?MYHOSTS).
|
||||||
|
|
||||||
|
|
|
@ -52,17 +52,7 @@
|
||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
-include("jid.hrl").
|
-include("jid.hrl").
|
||||||
|
|
||||||
%% Create the anonymous table if at least one virtual host has anonymous features enabled
|
|
||||||
%% Register to login / logout events
|
|
||||||
-record(anonymous, {us = {<<"">>, <<"">>} :: {binary(), binary()},
|
|
||||||
sid = ejabberd_sm:make_sid() :: ejabberd_sm:sid()}).
|
|
||||||
|
|
||||||
start(Host) ->
|
start(Host) ->
|
||||||
%% TODO: Check cluster mode
|
|
||||||
ejabberd_mnesia:create(?MODULE, anonymous, [{ram_copies, [node()]},
|
|
||||||
{type, bag},
|
|
||||||
{attributes, record_info(fields, anonymous)}]),
|
|
||||||
%% The hooks are needed to add / remove users from the anonymous tables
|
|
||||||
ejabberd_hooks:add(sm_register_connection_hook, Host,
|
ejabberd_hooks:add(sm_register_connection_hook, Host,
|
||||||
?MODULE, register_connection, 100),
|
?MODULE, register_connection, 100),
|
||||||
ejabberd_hooks:add(sm_remove_connection_hook, Host,
|
ejabberd_hooks:add(sm_remove_connection_hook, Host,
|
||||||
|
@ -119,56 +109,33 @@ allow_multiple_connections(Host) ->
|
||||||
fun(V) when is_boolean(V) -> V end,
|
fun(V) when is_boolean(V) -> V end,
|
||||||
false).
|
false).
|
||||||
|
|
||||||
%% Check if user exist in the anonymus database
|
|
||||||
anonymous_user_exist(User, Server) ->
|
anonymous_user_exist(User, Server) ->
|
||||||
LUser = jid:nodeprep(User),
|
lists:any(
|
||||||
LServer = jid:nameprep(Server),
|
fun({_LResource, Info}) ->
|
||||||
US = {LUser, LServer},
|
proplists:get_value(auth_module, Info) == ?MODULE
|
||||||
case catch mnesia:dirty_read({anonymous, US}) of
|
end, ejabberd_sm:get_user_info(User, Server)).
|
||||||
[] ->
|
|
||||||
false;
|
|
||||||
[_H|_T] ->
|
|
||||||
true
|
|
||||||
end.
|
|
||||||
|
|
||||||
%% Remove connection from Mnesia tables
|
|
||||||
remove_connection(SID, LUser, LServer) ->
|
|
||||||
US = {LUser, LServer},
|
|
||||||
F = fun () -> mnesia:delete_object({anonymous, US, SID})
|
|
||||||
end,
|
|
||||||
mnesia:transaction(F).
|
|
||||||
|
|
||||||
%% Register connection
|
%% Register connection
|
||||||
-spec register_connection(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> ok.
|
-spec register_connection(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> ok.
|
||||||
register_connection(SID,
|
register_connection(_SID,
|
||||||
#jid{luser = LUser, lserver = LServer}, Info) ->
|
#jid{luser = LUser, lserver = LServer}, Info) ->
|
||||||
AuthModule = proplists:get_value(auth_module, Info, undefined),
|
case proplists:get_value(auth_module, Info) of
|
||||||
case AuthModule == (?MODULE) of
|
?MODULE ->
|
||||||
true ->
|
ejabberd_hooks:run(register_user, LServer, [LUser, LServer]);
|
||||||
ejabberd_hooks:run(register_user, LServer,
|
false ->
|
||||||
[LUser, LServer]),
|
ok
|
||||||
US = {LUser, LServer},
|
|
||||||
mnesia:sync_dirty(fun () ->
|
|
||||||
mnesia:write(#anonymous{us = US,
|
|
||||||
sid = SID})
|
|
||||||
end);
|
|
||||||
false -> ok
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Remove an anonymous user from the anonymous users table
|
%% Remove an anonymous user from the anonymous users table
|
||||||
-spec unregister_connection(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> any().
|
-spec unregister_connection(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> any().
|
||||||
unregister_connection(SID,
|
unregister_connection(_SID,
|
||||||
#jid{luser = LUser, lserver = LServer}, _) ->
|
#jid{luser = LUser, lserver = LServer}, Info) ->
|
||||||
purge_hook(anonymous_user_exist(LUser, LServer), LUser,
|
case proplists:get_value(auth_module, Info) of
|
||||||
LServer),
|
?MODULE ->
|
||||||
remove_connection(SID, LUser, LServer).
|
ejabberd_hooks:run(remove_user, LServer, [LUser, LServer]);
|
||||||
|
_ ->
|
||||||
%% Launch the hook to purge user data only for anonymous users
|
ok
|
||||||
purge_hook(false, _LUser, _LServer) ->
|
end.
|
||||||
ok;
|
|
||||||
purge_hook(true, LUser, LServer) ->
|
|
||||||
ejabberd_hooks:run(anonymous_purge_hook, LServer,
|
|
||||||
[LUser, LServer]).
|
|
||||||
|
|
||||||
%% ---------------------------------
|
%% ---------------------------------
|
||||||
%% Specific anonymous auth functions
|
%% Specific anonymous auth functions
|
||||||
|
@ -258,8 +225,6 @@ get_password_s(User, Server) ->
|
||||||
Password
|
Password
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Returns true if the user exists in the DB or if an anonymous user is logged
|
|
||||||
%% under the given name
|
|
||||||
is_user_exists(User, Server) ->
|
is_user_exists(User, Server) ->
|
||||||
anonymous_user_exist(User, Server).
|
anonymous_user_exist(User, Server).
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@
|
||||||
user_resources/2,
|
user_resources/2,
|
||||||
kick_user/2,
|
kick_user/2,
|
||||||
get_session_pid/3,
|
get_session_pid/3,
|
||||||
|
get_user_info/2,
|
||||||
get_user_info/3,
|
get_user_info/3,
|
||||||
get_user_ip/3,
|
get_user_ip/3,
|
||||||
get_max_user_sessions/2,
|
get_max_user_sessions/2,
|
||||||
|
@ -215,6 +216,17 @@ get_user_ip(User, Server, Resource) ->
|
||||||
proplists:get_value(ip, Session#session.info)
|
proplists:get_value(ip, Session#session.info)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec get_user_info(binary(), binary()) -> [{binary(), info()}].
|
||||||
|
get_user_info(User, Server) ->
|
||||||
|
LUser = jid:nodeprep(User),
|
||||||
|
LServer = jid:nameprep(Server),
|
||||||
|
Mod = get_sm_backend(LServer),
|
||||||
|
Ss = online(Mod:get_sessions(LUser, LServer)),
|
||||||
|
[{LResource, [{node, node(Pid)}|Info]}
|
||||||
|
|| #session{usr = {_, _, LResource},
|
||||||
|
info = Info,
|
||||||
|
sid = {_, Pid}} <- clean_session_list(Ss)].
|
||||||
|
|
||||||
-spec get_user_info(binary(), binary(), binary()) -> info() | offline.
|
-spec get_user_info(binary(), binary(), binary()) -> info() | offline.
|
||||||
|
|
||||||
get_user_info(User, Server, Resource) ->
|
get_user_info(User, Server, Resource) ->
|
||||||
|
@ -228,9 +240,7 @@ get_user_info(User, Server, Resource) ->
|
||||||
Ss ->
|
Ss ->
|
||||||
Session = lists:max(Ss),
|
Session = lists:max(Ss),
|
||||||
Node = node(element(2, Session#session.sid)),
|
Node = node(element(2, Session#session.sid)),
|
||||||
Conn = proplists:get_value(conn, Session#session.info),
|
[{node, Node}|Session#session.info]
|
||||||
IP = proplists:get_value(ip, Session#session.info),
|
|
||||||
[{node, Node}, {conn, Conn}, {ip, IP}]
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec set_presence(sid(), binary(), binary(), binary(),
|
-spec set_presence(sid(), binary(), binary(), binary(),
|
||||||
|
|
|
@ -31,12 +31,13 @@
|
||||||
|
|
||||||
-export([start/0, start_module/2, start_module/3,
|
-export([start/0, start_module/2, start_module/3,
|
||||||
stop_module/2, stop_module_keep_config/2, get_opt/3,
|
stop_module/2, stop_module_keep_config/2, get_opt/3,
|
||||||
get_opt/4, get_opt_host/3, db_type/2, db_type/3,
|
get_opt/4, get_opt_host/3, opt_type/1,
|
||||||
get_module_opt/4, get_module_opt/5, get_module_opt_host/3,
|
get_module_opt/4, get_module_opt/5, get_module_opt_host/3,
|
||||||
loaded_modules/1, loaded_modules_with_opts/1,
|
loaded_modules/1, loaded_modules_with_opts/1,
|
||||||
get_hosts/2, get_module_proc/2, is_loaded/2,
|
get_hosts/2, get_module_proc/2, is_loaded/2,
|
||||||
start_modules/0, start_modules/1, stop_modules/0, stop_modules/1,
|
start_modules/0, start_modules/1, stop_modules/0, stop_modules/1,
|
||||||
opt_type/1, db_mod/2, db_mod/3]).
|
db_mod/2, db_mod/3, ram_db_mod/2, ram_db_mod/3,
|
||||||
|
db_type/2, db_type/3, ram_db_type/2, ram_db_type/3]).
|
||||||
|
|
||||||
%%-export([behaviour_info/1]).
|
%%-export([behaviour_info/1]).
|
||||||
|
|
||||||
|
@ -424,6 +425,43 @@ db_mod(Host, Module) when is_binary(Host) orelse Host == global ->
|
||||||
db_mod(Host, Opts, Module) when is_list(Opts) ->
|
db_mod(Host, Opts, Module) when is_list(Opts) ->
|
||||||
db_mod(db_type(Host, Opts, Module), Module).
|
db_mod(db_type(Host, Opts, Module), Module).
|
||||||
|
|
||||||
|
-spec ram_db_type(binary() | global, module()) -> db_type();
|
||||||
|
(opts(), module()) -> db_type().
|
||||||
|
ram_db_type(Opts, Module) when is_list(Opts) ->
|
||||||
|
ram_db_type(global, Opts, Module);
|
||||||
|
ram_db_type(Host, Module) when is_atom(Module) ->
|
||||||
|
case catch Module:mod_opt_type(ram_db_type) of
|
||||||
|
F when is_function(F) ->
|
||||||
|
case get_module_opt(Host, Module, ram_db_type, F) of
|
||||||
|
undefined -> ejabberd_config:default_ram_db(Host, Module);
|
||||||
|
Type -> Type
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
undefined
|
||||||
|
end.
|
||||||
|
|
||||||
|
-spec ram_db_type(binary(), opts(), module()) -> db_type().
|
||||||
|
ram_db_type(Host, Opts, Module) ->
|
||||||
|
case catch Module:mod_opt_type(ram_db_type) of
|
||||||
|
F when is_function(F) ->
|
||||||
|
case get_opt(ram_db_type, Opts, F) of
|
||||||
|
undefined -> ejabberd_config:default_ram_db(Host, Module);
|
||||||
|
Type -> Type
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
undefined
|
||||||
|
end.
|
||||||
|
|
||||||
|
-spec ram_db_mod(binary() | global | db_type(), module()) -> module().
|
||||||
|
ram_db_mod(Type, Module) when is_atom(Type), Type /= global ->
|
||||||
|
list_to_atom(atom_to_list(Module) ++ "_" ++ atom_to_list(Type));
|
||||||
|
ram_db_mod(Host, Module) when is_binary(Host) orelse Host == global ->
|
||||||
|
ram_db_mod(ram_db_type(Host, Module), Module).
|
||||||
|
|
||||||
|
-spec ram_db_mod(binary() | global, opts(), module()) -> module().
|
||||||
|
ram_db_mod(Host, Opts, Module) when is_list(Opts) ->
|
||||||
|
ram_db_mod(ram_db_type(Host, Opts, Module), Module).
|
||||||
|
|
||||||
-spec loaded_modules(binary()) -> [atom()].
|
-spec loaded_modules(binary()) -> [atom()].
|
||||||
|
|
||||||
loaded_modules(Host) ->
|
loaded_modules(Host) ->
|
||||||
|
|
143
src/mod_bosh.erl
143
src/mod_bosh.erl
|
@ -30,31 +30,25 @@
|
||||||
|
|
||||||
%%-define(ejabberd_debug, true).
|
%%-define(ejabberd_debug, true).
|
||||||
|
|
||||||
-behaviour(gen_server).
|
|
||||||
-behaviour(gen_mod).
|
-behaviour(gen_mod).
|
||||||
|
|
||||||
-export([start_link/0]).
|
-export([start_link/0]).
|
||||||
-export([start/2, stop/1, process/2, open_session/2,
|
-export([start/2, stop/1, process/2, open_session/2,
|
||||||
close_session/1, find_session/1]).
|
close_session/1, find_session/1]).
|
||||||
|
|
||||||
-export([init/1, handle_call/3, handle_cast/2,
|
-export([depends/2, mod_opt_type/1]).
|
||||||
handle_info/2, terminate/2, code_change/3,
|
|
||||||
depends/2, mod_opt_type/1]).
|
|
||||||
|
|
||||||
-include("ejabberd.hrl").
|
-include("ejabberd.hrl").
|
||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
-include_lib("stdlib/include/ms_transform.hrl").
|
-include_lib("stdlib/include/ms_transform.hrl").
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
-include("ejabberd_http.hrl").
|
-include("ejabberd_http.hrl").
|
||||||
|
|
||||||
-include("bosh.hrl").
|
-include("bosh.hrl").
|
||||||
|
|
||||||
-record(bosh, {sid = <<"">> :: binary() | '_',
|
-callback init() -> any().
|
||||||
timestamp = p1_time_compat:timestamp() :: erlang:timestamp() | '_',
|
-callback open_session(binary(), pid()) -> any().
|
||||||
pid = self() :: pid() | '$1'}).
|
-callback close_session(binary()) -> any().
|
||||||
|
-callback find_session(binary()) -> {ok, pid()} | error.
|
||||||
-record(state, {}).
|
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% API
|
%%% API
|
||||||
|
@ -114,137 +108,35 @@ get_human_html_xmlel() ->
|
||||||
"client that supports it.">>}]}]}]}.
|
"client that supports it.">>}]}]}]}.
|
||||||
|
|
||||||
open_session(SID, Pid) ->
|
open_session(SID, Pid) ->
|
||||||
Session = #bosh{sid = SID, timestamp = p1_time_compat:timestamp(), pid = Pid},
|
Mod = gen_mod:ram_db_mod(global, ?MODULE),
|
||||||
lists:foreach(
|
Mod:open_session(SID, Pid).
|
||||||
fun(Node) when Node == node() ->
|
|
||||||
gen_server:call(?MODULE, {write, Session});
|
|
||||||
(Node) ->
|
|
||||||
cluster_send({?MODULE, Node}, {write, Session})
|
|
||||||
end, ejabberd_cluster:get_nodes()).
|
|
||||||
|
|
||||||
close_session(SID) ->
|
close_session(SID) ->
|
||||||
case mnesia:dirty_read(bosh, SID) of
|
Mod = gen_mod:ram_db_mod(global, ?MODULE),
|
||||||
[Session] ->
|
Mod:close_session(SID).
|
||||||
lists:foreach(
|
|
||||||
fun(Node) when Node == node() ->
|
|
||||||
gen_server:call(?MODULE, {delete, Session});
|
|
||||||
(Node) ->
|
|
||||||
cluster_send({?MODULE, Node}, {delete, Session})
|
|
||||||
end, ejabberd_cluster:get_nodes());
|
|
||||||
[] ->
|
|
||||||
ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
write_session(#bosh{pid = Pid1, sid = SID, timestamp = T1} = S1) ->
|
|
||||||
case mnesia:dirty_read(bosh, SID) of
|
|
||||||
[#bosh{pid = Pid2, timestamp = T2} = S2] ->
|
|
||||||
if Pid1 == Pid2 ->
|
|
||||||
mnesia:dirty_write(S1);
|
|
||||||
T1 < T2 ->
|
|
||||||
cluster_send(Pid2, replaced),
|
|
||||||
mnesia:dirty_write(S1);
|
|
||||||
true ->
|
|
||||||
cluster_send(Pid1, replaced),
|
|
||||||
mnesia:dirty_write(S2)
|
|
||||||
end;
|
|
||||||
[] ->
|
|
||||||
mnesia:dirty_write(S1)
|
|
||||||
end.
|
|
||||||
|
|
||||||
delete_session(#bosh{sid = SID, pid = Pid1}) ->
|
|
||||||
case mnesia:dirty_read(bosh, SID) of
|
|
||||||
[#bosh{pid = Pid2}] ->
|
|
||||||
if Pid1 == Pid2 ->
|
|
||||||
mnesia:dirty_delete(bosh, SID);
|
|
||||||
true ->
|
|
||||||
ok
|
|
||||||
end;
|
|
||||||
[] ->
|
|
||||||
ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
find_session(SID) ->
|
find_session(SID) ->
|
||||||
case mnesia:dirty_read(bosh, SID) of
|
Mod = gen_mod:ram_db_mod(global, ?MODULE),
|
||||||
[#bosh{pid = Pid}] ->
|
Mod:find_session(SID).
|
||||||
{ok, Pid};
|
|
||||||
[] ->
|
|
||||||
error
|
|
||||||
end.
|
|
||||||
|
|
||||||
start(Host, Opts) ->
|
start(Host, Opts) ->
|
||||||
setup_database(),
|
|
||||||
start_jiffy(Opts),
|
start_jiffy(Opts),
|
||||||
TmpSup = gen_mod:get_module_proc(Host, ?PROCNAME),
|
TmpSup = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||||
TmpSupSpec = {TmpSup,
|
TmpSupSpec = {TmpSup,
|
||||||
{ejabberd_tmp_sup, start_link, [TmpSup, ejabberd_bosh]},
|
{ejabberd_tmp_sup, start_link, [TmpSup, ejabberd_bosh]},
|
||||||
permanent, infinity, supervisor, [ejabberd_tmp_sup]},
|
permanent, infinity, supervisor, [ejabberd_tmp_sup]},
|
||||||
ProcSpec = {?MODULE,
|
supervisor:start_child(ejabberd_sup, TmpSupSpec),
|
||||||
{?MODULE, start_link, []},
|
Mod = gen_mod:ram_db_mod(global, ?MODULE),
|
||||||
transient, 2000, worker, [?MODULE]},
|
Mod:init().
|
||||||
case supervisor:start_child(ejabberd_sup, ProcSpec) of
|
|
||||||
{ok, _} ->
|
|
||||||
supervisor:start_child(ejabberd_sup, TmpSupSpec);
|
|
||||||
{error, {already_started, _}} ->
|
|
||||||
supervisor:start_child(ejabberd_sup, TmpSupSpec);
|
|
||||||
Err ->
|
|
||||||
Err
|
|
||||||
end.
|
|
||||||
|
|
||||||
stop(Host) ->
|
stop(Host) ->
|
||||||
TmpSup = gen_mod:get_module_proc(Host, ?PROCNAME),
|
TmpSup = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||||
supervisor:terminate_child(ejabberd_sup, TmpSup),
|
supervisor:terminate_child(ejabberd_sup, TmpSup),
|
||||||
supervisor:delete_child(ejabberd_sup, TmpSup).
|
supervisor:delete_child(ejabberd_sup, TmpSup).
|
||||||
|
|
||||||
%%%===================================================================
|
|
||||||
%%% gen_server callbacks
|
|
||||||
%%%===================================================================
|
|
||||||
init([]) ->
|
|
||||||
{ok, #state{}}.
|
|
||||||
|
|
||||||
handle_call({write, Session}, _From, State) ->
|
|
||||||
Res = write_session(Session),
|
|
||||||
{reply, Res, State};
|
|
||||||
handle_call({delete, Session}, _From, State) ->
|
|
||||||
Res = delete_session(Session),
|
|
||||||
{reply, Res, State};
|
|
||||||
handle_call(_Request, _From, State) ->
|
|
||||||
Reply = ok,
|
|
||||||
{reply, Reply, State}.
|
|
||||||
|
|
||||||
handle_cast(_Msg, State) ->
|
|
||||||
{noreply, State}.
|
|
||||||
|
|
||||||
handle_info({write, Session}, State) ->
|
|
||||||
write_session(Session),
|
|
||||||
{noreply, State};
|
|
||||||
handle_info({delete, Session}, State) ->
|
|
||||||
delete_session(Session),
|
|
||||||
{noreply, State};
|
|
||||||
handle_info(_Info, State) ->
|
|
||||||
?ERROR_MSG("got unexpected info: ~p", [_Info]),
|
|
||||||
{noreply, State}.
|
|
||||||
|
|
||||||
terminate(_Reason, _State) ->
|
|
||||||
ok.
|
|
||||||
|
|
||||||
code_change(_OldVsn, State, _Extra) ->
|
|
||||||
{ok, State}.
|
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
setup_database() ->
|
|
||||||
case catch mnesia:table_info(bosh, attributes) of
|
|
||||||
[sid, pid] ->
|
|
||||||
mnesia:delete_table(bosh);
|
|
||||||
_ ->
|
|
||||||
ok
|
|
||||||
end,
|
|
||||||
ejabberd_mnesia:create(?MODULE, bosh,
|
|
||||||
[{ram_copies, [node()]}, {local_content, true},
|
|
||||||
{attributes, record_info(fields, bosh)}]),
|
|
||||||
mnesia:add_table_copy(bosh, node(), ram_copies).
|
|
||||||
|
|
||||||
start_jiffy(Opts) ->
|
start_jiffy(Opts) ->
|
||||||
case gen_mod:get_opt(json, Opts,
|
case gen_mod:get_opt(json, Opts,
|
||||||
fun(false) -> false;
|
fun(false) -> false;
|
||||||
|
@ -272,9 +164,6 @@ get_type(Hdrs) ->
|
||||||
xml
|
xml
|
||||||
end.
|
end.
|
||||||
|
|
||||||
cluster_send(NodePid, Msg) ->
|
|
||||||
erlang:send(NodePid, Msg, [noconnect, nosuspend]).
|
|
||||||
|
|
||||||
depends(_Host, _Opts) ->
|
depends(_Host, _Opts) ->
|
||||||
[].
|
[].
|
||||||
|
|
||||||
|
@ -292,5 +181,7 @@ mod_opt_type(max_pause) ->
|
||||||
fun (I) when is_integer(I), I > 0 -> I end;
|
fun (I) when is_integer(I), I > 0 -> I end;
|
||||||
mod_opt_type(prebind) ->
|
mod_opt_type(prebind) ->
|
||||||
fun (B) when is_boolean(B) -> B end;
|
fun (B) when is_boolean(B) -> B end;
|
||||||
|
mod_opt_type(ram_db_type) ->
|
||||||
|
fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
||||||
mod_opt_type(_) ->
|
mod_opt_type(_) ->
|
||||||
[json, max_concat, max_inactivity, max_pause, prebind].
|
[json, max_concat, max_inactivity, max_pause, prebind, ram_db_type].
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% Created : 12 Jan 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||||
|
%%%
|
||||||
|
%%%
|
||||||
|
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
|
||||||
|
%%%
|
||||||
|
%%% This program is free software; you can redistribute it and/or
|
||||||
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
%%% published by the Free Software Foundation; either version 2 of the
|
||||||
|
%%% License, or (at your option) any later version.
|
||||||
|
%%%
|
||||||
|
%%% This program is distributed in the hope that it will be useful,
|
||||||
|
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
%%% General Public License for more details.
|
||||||
|
%%%
|
||||||
|
%%% You should have received a copy of the GNU General Public License along
|
||||||
|
%%% with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
%%%
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
-module(mod_bosh_mnesia).
|
||||||
|
|
||||||
|
-behaviour(gen_server).
|
||||||
|
-behaviour(mod_bosh).
|
||||||
|
|
||||||
|
%% mod_bosh API
|
||||||
|
-export([init/0, open_session/2, close_session/1, find_session/1]).
|
||||||
|
|
||||||
|
%% gen_server callbacks
|
||||||
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||||
|
terminate/2, code_change/3]).
|
||||||
|
|
||||||
|
-include("logger.hrl").
|
||||||
|
|
||||||
|
-record(bosh, {sid = <<"">> :: binary() | '_',
|
||||||
|
timestamp = p1_time_compat:timestamp() :: erlang:timestamp() | '_',
|
||||||
|
pid = self() :: pid() | '$1'}).
|
||||||
|
|
||||||
|
-record(state, {}).
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% API
|
||||||
|
%%%===================================================================
|
||||||
|
init() ->
|
||||||
|
case gen_server:start_link({local, ?MODULE}, ?MODULE, [], []) of
|
||||||
|
{ok, _Pid} ->
|
||||||
|
ok;
|
||||||
|
Err ->
|
||||||
|
Err
|
||||||
|
end.
|
||||||
|
|
||||||
|
open_session(SID, Pid) ->
|
||||||
|
Session = #bosh{sid = SID, timestamp = p1_time_compat:timestamp(), pid = Pid},
|
||||||
|
lists:foreach(
|
||||||
|
fun(Node) when Node == node() ->
|
||||||
|
gen_server:call(?MODULE, {write, Session});
|
||||||
|
(Node) ->
|
||||||
|
cluster_send({?MODULE, Node}, {write, Session})
|
||||||
|
end, ejabberd_cluster:get_nodes()).
|
||||||
|
|
||||||
|
close_session(SID) ->
|
||||||
|
case mnesia:dirty_read(bosh, SID) of
|
||||||
|
[Session] ->
|
||||||
|
lists:foreach(
|
||||||
|
fun(Node) when Node == node() ->
|
||||||
|
gen_server:call(?MODULE, {delete, Session});
|
||||||
|
(Node) ->
|
||||||
|
cluster_send({?MODULE, Node}, {delete, Session})
|
||||||
|
end, ejabberd_cluster:get_nodes());
|
||||||
|
[] ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
find_session(SID) ->
|
||||||
|
case mnesia:dirty_read(bosh, SID) of
|
||||||
|
[#bosh{pid = Pid}] ->
|
||||||
|
{ok, Pid};
|
||||||
|
[] ->
|
||||||
|
error
|
||||||
|
end.
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% gen_server callbacks
|
||||||
|
%%%===================================================================
|
||||||
|
init([]) ->
|
||||||
|
setup_database(),
|
||||||
|
{ok, #state{}}.
|
||||||
|
|
||||||
|
handle_call({write, Session}, _From, State) ->
|
||||||
|
Res = write_session(Session),
|
||||||
|
{reply, Res, State};
|
||||||
|
handle_call({delete, Session}, _From, State) ->
|
||||||
|
Res = delete_session(Session),
|
||||||
|
{reply, Res, State};
|
||||||
|
handle_call(_Request, _From, State) ->
|
||||||
|
Reply = ok,
|
||||||
|
{reply, Reply, State}.
|
||||||
|
|
||||||
|
handle_cast(_Msg, State) ->
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
handle_info({write, Session}, State) ->
|
||||||
|
write_session(Session),
|
||||||
|
{noreply, State};
|
||||||
|
handle_info({delete, Session}, State) ->
|
||||||
|
delete_session(Session),
|
||||||
|
{noreply, State};
|
||||||
|
handle_info(_Info, State) ->
|
||||||
|
?ERROR_MSG("got unexpected info: ~p", [_Info]),
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
terminate(_Reason, _State) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
|
{ok, State}.
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% Internal functions
|
||||||
|
%%%===================================================================
|
||||||
|
write_session(#bosh{pid = Pid1, sid = SID, timestamp = T1} = S1) ->
|
||||||
|
case mnesia:dirty_read(bosh, SID) of
|
||||||
|
[#bosh{pid = Pid2, timestamp = T2} = S2] ->
|
||||||
|
if Pid1 == Pid2 ->
|
||||||
|
mnesia:dirty_write(S1);
|
||||||
|
T1 < T2 ->
|
||||||
|
cluster_send(Pid2, replaced),
|
||||||
|
mnesia:dirty_write(S1);
|
||||||
|
true ->
|
||||||
|
cluster_send(Pid1, replaced),
|
||||||
|
mnesia:dirty_write(S2)
|
||||||
|
end;
|
||||||
|
[] ->
|
||||||
|
mnesia:dirty_write(S1)
|
||||||
|
end.
|
||||||
|
|
||||||
|
delete_session(#bosh{sid = SID, pid = Pid1}) ->
|
||||||
|
case mnesia:dirty_read(bosh, SID) of
|
||||||
|
[#bosh{pid = Pid2}] ->
|
||||||
|
if Pid1 == Pid2 ->
|
||||||
|
mnesia:dirty_delete(bosh, SID);
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end;
|
||||||
|
[] ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
cluster_send(NodePid, Msg) ->
|
||||||
|
erlang:send(NodePid, Msg, [noconnect, nosuspend]).
|
||||||
|
|
||||||
|
setup_database() ->
|
||||||
|
case catch mnesia:table_info(bosh, attributes) of
|
||||||
|
[sid, pid] ->
|
||||||
|
mnesia:delete_table(bosh);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
ejabberd_mnesia:create(?MODULE, bosh,
|
||||||
|
[{ram_copies, [node()]}, {local_content, true},
|
||||||
|
{attributes, record_info(fields, bosh)}]),
|
||||||
|
mnesia:add_table_copy(bosh, node(), ram_copies).
|
|
@ -139,8 +139,6 @@ start(ServerHost, Opts) ->
|
||||||
true) of
|
true) of
|
||||||
true ->
|
true ->
|
||||||
ejabberd_hooks:add(remove_user, ServerHost, ?MODULE,
|
ejabberd_hooks:add(remove_user, ServerHost, ?MODULE,
|
||||||
remove_user, 50),
|
|
||||||
ejabberd_hooks:add(anonymous_purge_hook, ServerHost, ?MODULE,
|
|
||||||
remove_user, 50);
|
remove_user, 50);
|
||||||
false ->
|
false ->
|
||||||
ok
|
ok
|
||||||
|
@ -162,8 +160,6 @@ stop(ServerHost) ->
|
||||||
true) of
|
true) of
|
||||||
true ->
|
true ->
|
||||||
ejabberd_hooks:delete(remove_user, ServerHost, ?MODULE,
|
ejabberd_hooks:delete(remove_user, ServerHost, ?MODULE,
|
||||||
remove_user, 50),
|
|
||||||
ejabberd_hooks:delete(anonymous_purge_hook, ServerHost, ?MODULE,
|
|
||||||
remove_user, 50);
|
remove_user, 50);
|
||||||
false ->
|
false ->
|
||||||
ok
|
ok
|
||||||
|
|
|
@ -104,8 +104,6 @@ start(Host, Opts) ->
|
||||||
get_room_config, 50),
|
get_room_config, 50),
|
||||||
ejabberd_hooks:add(set_room_option, Host, ?MODULE,
|
ejabberd_hooks:add(set_room_option, Host, ?MODULE,
|
||||||
set_room_option, 50),
|
set_room_option, 50),
|
||||||
ejabberd_hooks:add(anonymous_purge_hook, Host, ?MODULE,
|
|
||||||
remove_user, 50),
|
|
||||||
case gen_mod:get_opt(assume_mam_usage, Opts,
|
case gen_mod:get_opt(assume_mam_usage, Opts,
|
||||||
fun(B) when is_boolean(B) -> B end, false) of
|
fun(B) when is_boolean(B) -> B end, false) of
|
||||||
true ->
|
true ->
|
||||||
|
@ -154,8 +152,6 @@ stop(Host) ->
|
||||||
get_room_config, 50),
|
get_room_config, 50),
|
||||||
ejabberd_hooks:delete(set_room_option, Host, ?MODULE,
|
ejabberd_hooks:delete(set_room_option, Host, ?MODULE,
|
||||||
set_room_option, 50),
|
set_room_option, 50),
|
||||||
ejabberd_hooks:delete(anonymous_purge_hook, Host,
|
|
||||||
?MODULE, remove_user, 50),
|
|
||||||
case gen_mod:get_module_opt(Host, ?MODULE, assume_mam_usage,
|
case gen_mod:get_module_opt(Host, ?MODULE, assume_mam_usage,
|
||||||
fun(B) when is_boolean(B) -> B end, false) of
|
fun(B) when is_boolean(B) -> B end, false) of
|
||||||
true ->
|
true ->
|
||||||
|
|
361
src/mod_muc.erl
361
src/mod_muc.erl
|
@ -49,12 +49,20 @@
|
||||||
process_register/1,
|
process_register/1,
|
||||||
process_muc_unique/1,
|
process_muc_unique/1,
|
||||||
process_mucsub/1,
|
process_mucsub/1,
|
||||||
broadcast_service_message/2,
|
broadcast_service_message/3,
|
||||||
export/1,
|
export/1,
|
||||||
import_info/0,
|
import_info/0,
|
||||||
import/5,
|
import/5,
|
||||||
import_start/2,
|
import_start/2,
|
||||||
opts_to_binary/1,
|
opts_to_binary/1,
|
||||||
|
find_online_room/2,
|
||||||
|
register_online_room/3,
|
||||||
|
get_online_rooms/1,
|
||||||
|
count_online_rooms/1,
|
||||||
|
register_online_user/4,
|
||||||
|
unregister_online_user/4,
|
||||||
|
count_online_rooms_by_user/3,
|
||||||
|
get_online_rooms_by_user/3,
|
||||||
can_use_nick/4]).
|
can_use_nick/4]).
|
||||||
|
|
||||||
-export([init/1, handle_call/3, handle_cast/2,
|
-export([init/1, handle_call/3, handle_cast/2,
|
||||||
|
@ -63,7 +71,6 @@
|
||||||
|
|
||||||
-include("ejabberd.hrl").
|
-include("ejabberd.hrl").
|
||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
-include_lib("stdlib/include/ms_transform.hrl").
|
|
||||||
-include("xmpp.hrl").
|
-include("xmpp.hrl").
|
||||||
-include("mod_muc.hrl").
|
-include("mod_muc.hrl").
|
||||||
|
|
||||||
|
@ -88,6 +95,17 @@
|
||||||
-callback get_rooms(binary(), binary()) -> [#muc_room{}].
|
-callback get_rooms(binary(), binary()) -> [#muc_room{}].
|
||||||
-callback get_nick(binary(), binary(), jid()) -> binary() | error.
|
-callback get_nick(binary(), binary(), jid()) -> binary() | error.
|
||||||
-callback set_nick(binary(), binary(), jid(), binary()) -> {atomic, ok | false}.
|
-callback set_nick(binary(), binary(), jid(), binary()) -> {atomic, ok | false}.
|
||||||
|
-callback register_online_room(binary(), binary(), pid()) -> any().
|
||||||
|
-callback unregister_online_room(binary(), binary(), pid()) -> any().
|
||||||
|
-callback find_online_room(binary(), binary()) -> {ok, pid()} | error.
|
||||||
|
-callback get_online_rooms(binary(), undefined | rsm_set()) -> [{binary(), binary(), pid()}].
|
||||||
|
-callback count_online_rooms(binary()) -> non_neg_integer().
|
||||||
|
-callback rsm_supported() -> boolean().
|
||||||
|
-callback register_online_user(ljid(), binary(), binary()) -> any().
|
||||||
|
-callback unregister_online_user(ljid(), binary(), binary()) -> any().
|
||||||
|
-callback count_online_rooms_by_user(binary(), binary()) -> non_neg_integer().
|
||||||
|
-callback get_online_rooms_by_user(binary(), binary()) -> [{binary(), binary()}].
|
||||||
|
-callback handle_event(term()) -> any().
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% API
|
%% API
|
||||||
|
@ -114,16 +132,17 @@ depends(_Host, _Opts) ->
|
||||||
[{mod_mam, soft}].
|
[{mod_mam, soft}].
|
||||||
|
|
||||||
shutdown_rooms(Host) ->
|
shutdown_rooms(Host) ->
|
||||||
|
RMod = gen_mod:ram_db_mod(Host, ?MODULE),
|
||||||
MyHost = gen_mod:get_module_opt_host(Host, mod_muc,
|
MyHost = gen_mod:get_module_opt_host(Host, mod_muc,
|
||||||
<<"conference.@HOST@">>),
|
<<"conference.@HOST@">>),
|
||||||
Rooms = mnesia:dirty_select(muc_online_room,
|
Rooms = RMod:get_online_rooms(MyHost, undefined),
|
||||||
[{#muc_online_room{name_host = '$1',
|
lists:filter(
|
||||||
pid = '$2'},
|
fun({_, _, Pid}) when node(Pid) == node() ->
|
||||||
[{'==', {element, 2, '$1'}, MyHost},
|
Pid ! shutdown,
|
||||||
{'==', {node, '$2'}, node()}],
|
true;
|
||||||
['$2']}]),
|
(_) ->
|
||||||
[Pid ! shutdown || Pid <- Rooms],
|
false
|
||||||
Rooms.
|
end, Rooms).
|
||||||
|
|
||||||
%% This function is called by a room in three situations:
|
%% This function is called by a room in three situations:
|
||||||
%% A) The owner of the room destroyed it
|
%% A) The owner of the room destroyed it
|
||||||
|
@ -165,6 +184,48 @@ can_use_nick(ServerHost, Host, JID, Nick) ->
|
||||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||||
Mod:can_use_nick(LServer, Host, JID, Nick).
|
Mod:can_use_nick(LServer, Host, JID, Nick).
|
||||||
|
|
||||||
|
-spec find_online_room(binary(), binary()) -> {ok, pid()} | error.
|
||||||
|
find_online_room(Room, Host) ->
|
||||||
|
ServerHost = ejabberd_router:host_of_route(Host),
|
||||||
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
|
RMod:find_online_room(Room, Host).
|
||||||
|
|
||||||
|
-spec register_online_room(binary(), binary(), pid()) -> any().
|
||||||
|
register_online_room(Room, Host, Pid) ->
|
||||||
|
ServerHost = ejabberd_router:host_of_route(Host),
|
||||||
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
|
RMod:register_online_room(Room, Host, Pid).
|
||||||
|
|
||||||
|
-spec get_online_rooms(binary()) -> [{binary(), binary(), pid()}].
|
||||||
|
get_online_rooms(Host) ->
|
||||||
|
ServerHost = ejabberd_router:host_of_route(Host),
|
||||||
|
get_online_rooms(ServerHost, Host).
|
||||||
|
|
||||||
|
-spec count_online_rooms(binary()) -> non_neg_integer().
|
||||||
|
count_online_rooms(Host) ->
|
||||||
|
ServerHost = ejabberd_router:host_of_route(Host),
|
||||||
|
count_online_rooms(ServerHost, Host).
|
||||||
|
|
||||||
|
-spec register_online_user(binary(), ljid(), binary(), binary()) -> any().
|
||||||
|
register_online_user(ServerHost, LJID, Name, Host) ->
|
||||||
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
|
RMod:register_online_user(LJID, Name, Host).
|
||||||
|
|
||||||
|
-spec unregister_online_user(binary(), ljid(), binary(), binary()) -> any().
|
||||||
|
unregister_online_user(ServerHost, LJID, Name, Host) ->
|
||||||
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
|
RMod:unregister_online_user(LJID, Name, Host).
|
||||||
|
|
||||||
|
-spec count_online_rooms_by_user(binary(), binary(), binary()) -> non_neg_integer().
|
||||||
|
count_online_rooms_by_user(ServerHost, LUser, LServer) ->
|
||||||
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
|
RMod:count_online_rooms_by_user(LUser, LServer).
|
||||||
|
|
||||||
|
-spec get_online_rooms_by_user(binary(), binary(), binary()) -> [{binary(), binary()}].
|
||||||
|
get_online_rooms_by_user(ServerHost, LUser, LServer) ->
|
||||||
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
|
RMod:get_online_rooms_by_user(LUser, LServer).
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
@ -175,16 +236,9 @@ init([Host, Opts]) ->
|
||||||
MyHost = gen_mod:get_opt_host(Host, Opts,
|
MyHost = gen_mod:get_opt_host(Host, Opts,
|
||||||
<<"conference.@HOST@">>),
|
<<"conference.@HOST@">>),
|
||||||
Mod = gen_mod:db_mod(Host, Opts, ?MODULE),
|
Mod = gen_mod:db_mod(Host, Opts, ?MODULE),
|
||||||
|
RMod = gen_mod:ram_db_mod(Host, Opts, ?MODULE),
|
||||||
Mod:init(Host, [{host, MyHost}|Opts]),
|
Mod:init(Host, [{host, MyHost}|Opts]),
|
||||||
update_tables(),
|
RMod:init(Host, [{host, MyHost}|Opts]),
|
||||||
ejabberd_mnesia:create(?MODULE, muc_online_room,
|
|
||||||
[{ram_copies, [node()]},
|
|
||||||
{type, ordered_set},
|
|
||||||
{attributes, record_info(fields, muc_online_room)}]),
|
|
||||||
mnesia:add_table_copy(muc_online_room, node(), ram_copies),
|
|
||||||
catch ets:new(muc_online_users, [bag, named_table, public, {keypos, 2}]),
|
|
||||||
clean_table_from_bad_node(node(), MyHost),
|
|
||||||
mnesia:subscribe(system),
|
|
||||||
Access = gen_mod:get_opt(access, Opts,
|
Access = gen_mod:get_opt(access, Opts,
|
||||||
fun acl:access_rules_validator/1, all),
|
fun acl:access_rules_validator/1, all),
|
||||||
AccessCreate = gen_mod:get_opt(access_create, Opts,
|
AccessCreate = gen_mod:get_opt(access_create, Opts,
|
||||||
|
@ -298,7 +352,8 @@ handle_call({create, Room, From, Nick, Opts}, _From,
|
||||||
Room, HistorySize,
|
Room, HistorySize,
|
||||||
RoomShaper, From,
|
RoomShaper, From,
|
||||||
Nick, NewOpts),
|
Nick, NewOpts),
|
||||||
register_room(Host, Room, Pid),
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
|
RMod:register_online_room(Room, Host, Pid),
|
||||||
{reply, ok, State}.
|
{reply, ok, State}.
|
||||||
|
|
||||||
handle_cast(_Msg, State) -> {noreply, State}.
|
handle_cast(_Msg, State) -> {noreply, State}.
|
||||||
|
@ -317,18 +372,15 @@ handle_info({route, From, To, Packet},
|
||||||
ok
|
ok
|
||||||
end,
|
end,
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_info({room_destroyed, RoomHost, Pid}, State) ->
|
handle_info({room_destroyed, {Room, Host}, Pid}, State) ->
|
||||||
F = fun () ->
|
ServerHost = State#state.server_host,
|
||||||
mnesia:delete_object(#muc_online_room{name_host =
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
RoomHost,
|
RMod:unregister_online_room(Room, Host, Pid),
|
||||||
pid = Pid})
|
|
||||||
end,
|
|
||||||
mnesia:transaction(F),
|
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_info({mnesia_system_event, {mnesia_down, Node}}, State) ->
|
handle_info(Event, #state{server_host = LServer} = State) ->
|
||||||
clean_table_from_bad_node(Node),
|
RMod = gen_mod:ram_db_mod(LServer, ?MODULE),
|
||||||
{noreply, State};
|
RMod:handle_event(Event),
|
||||||
handle_info(_Info, State) -> {noreply, State}.
|
{noreply, State}.
|
||||||
|
|
||||||
terminate(_Reason, #state{host = MyHost}) ->
|
terminate(_Reason, #state{host = MyHost}) ->
|
||||||
ejabberd_router:unregister_route(MyHost),
|
ejabberd_router:unregister_route(MyHost),
|
||||||
|
@ -374,7 +426,7 @@ do_route1(Host, ServerHost, Access, _HistorySize, _RoomShaper,
|
||||||
case acl:match_rule(ServerHost, AccessAdmin, From) of
|
case acl:match_rule(ServerHost, AccessAdmin, From) of
|
||||||
allow ->
|
allow ->
|
||||||
Msg = xmpp:get_text(Body),
|
Msg = xmpp:get_text(Body),
|
||||||
broadcast_service_message(Host, Msg);
|
broadcast_service_message(ServerHost, Host, Msg);
|
||||||
deny ->
|
deny ->
|
||||||
ErrText = <<"Only service administrators are allowed "
|
ErrText = <<"Only service administrators are allowed "
|
||||||
"to send service messages">>,
|
"to send service messages">>,
|
||||||
|
@ -390,8 +442,9 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper,
|
||||||
From, To, Packet, DefRoomOpts) ->
|
From, To, Packet, DefRoomOpts) ->
|
||||||
{_AccessRoute, AccessCreate, _AccessAdmin, _AccessPersistent} = Access,
|
{_AccessRoute, AccessCreate, _AccessAdmin, _AccessPersistent} = Access,
|
||||||
{Room, _, Nick} = jid:tolower(To),
|
{Room, _, Nick} = jid:tolower(To),
|
||||||
case mnesia:dirty_read(muc_online_room, {Room, Host}) of
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
[] ->
|
case RMod:find_online_room(Room, Host) of
|
||||||
|
error ->
|
||||||
case is_create_request(Packet) of
|
case is_create_request(Packet) of
|
||||||
true ->
|
true ->
|
||||||
case check_user_can_create_room(
|
case check_user_can_create_room(
|
||||||
|
@ -402,7 +455,7 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper,
|
||||||
Host, ServerHost, Access,
|
Host, ServerHost, Access,
|
||||||
Room, HistorySize,
|
Room, HistorySize,
|
||||||
RoomShaper, From, Nick, DefRoomOpts),
|
RoomShaper, From, Nick, DefRoomOpts),
|
||||||
register_room(Host, Room, Pid),
|
RMod:register_online_room(Room, Host, Pid),
|
||||||
mod_muc_room:route(Pid, From, Nick, Packet),
|
mod_muc_room:route(Pid, From, Nick, Packet),
|
||||||
ok;
|
ok;
|
||||||
false ->
|
false ->
|
||||||
|
@ -417,8 +470,7 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper,
|
||||||
Err = xmpp:err_item_not_found(ErrText, Lang),
|
Err = xmpp:err_item_not_found(ErrText, Lang),
|
||||||
ejabberd_router:route_error(To, From, Packet, Err)
|
ejabberd_router:route_error(To, From, Packet, Err)
|
||||||
end;
|
end;
|
||||||
[R] ->
|
{ok, Pid} ->
|
||||||
Pid = R#muc_online_room.pid,
|
|
||||||
?DEBUG("MUC: send to process ~p~n", [Pid]),
|
?DEBUG("MUC: send to process ~p~n", [Pid]),
|
||||||
mod_muc_room:route(Pid, From, Nick, Packet),
|
mod_muc_room:route(Pid, From, Nick, Packet),
|
||||||
ok
|
ok
|
||||||
|
@ -462,15 +514,20 @@ process_disco_info(#iq{type = set, lang = Lang} = IQ) ->
|
||||||
process_disco_info(#iq{type = get, to = To, lang = Lang,
|
process_disco_info(#iq{type = get, to = To, lang = Lang,
|
||||||
sub_els = [#disco_info{node = <<"">>}]} = IQ) ->
|
sub_els = [#disco_info{node = <<"">>}]} = IQ) ->
|
||||||
ServerHost = ejabberd_router:host_of_route(To#jid.lserver),
|
ServerHost = ejabberd_router:host_of_route(To#jid.lserver),
|
||||||
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
X = ejabberd_hooks:run_fold(disco_info, ServerHost, [],
|
X = ejabberd_hooks:run_fold(disco_info, ServerHost, [],
|
||||||
[ServerHost, ?MODULE, <<"">>, Lang]),
|
[ServerHost, ?MODULE, <<"">>, Lang]),
|
||||||
MAMFeatures = case gen_mod:is_loaded(ServerHost, mod_mam) of
|
MAMFeatures = case gen_mod:is_loaded(ServerHost, mod_mam) of
|
||||||
true -> [?NS_MAM_TMP, ?NS_MAM_0, ?NS_MAM_1];
|
true -> [?NS_MAM_TMP, ?NS_MAM_0, ?NS_MAM_1];
|
||||||
false -> []
|
false -> []
|
||||||
end,
|
end,
|
||||||
|
RSMFeatures = case RMod:rsm_supported() of
|
||||||
|
true -> [?NS_RSM];
|
||||||
|
false -> []
|
||||||
|
end,
|
||||||
Features = [?NS_DISCO_INFO, ?NS_DISCO_ITEMS,
|
Features = [?NS_DISCO_INFO, ?NS_DISCO_ITEMS,
|
||||||
?NS_REGISTER, ?NS_MUC, ?NS_RSM,
|
?NS_REGISTER, ?NS_MUC, ?NS_VCARD, ?NS_MUCSUB, ?NS_MUC_UNIQUE
|
||||||
?NS_VCARD, ?NS_MUCSUB, ?NS_MUC_UNIQUE | MAMFeatures],
|
| RSMFeatures ++ MAMFeatures],
|
||||||
Identity = #identity{category = <<"conference">>,
|
Identity = #identity{category = <<"conference">>,
|
||||||
type = <<"text">>,
|
type = <<"text">>,
|
||||||
name = translate:translate(Lang, <<"Chatrooms">>)},
|
name = translate:translate(Lang, <<"Chatrooms">>)},
|
||||||
|
@ -497,7 +554,8 @@ process_disco_items(#iq{type = get, from = From, to = To, lang = Lang,
|
||||||
ServerHost, ?MODULE, max_rooms_discoitems,
|
ServerHost, ?MODULE, max_rooms_discoitems,
|
||||||
fun(I) when is_integer(I), I>=0 -> I end,
|
fun(I) when is_integer(I), I>=0 -> I end,
|
||||||
100),
|
100),
|
||||||
case iq_disco_items(Host, From, Lang, MaxRoomsDiscoItems, Node, RSM) of
|
case iq_disco_items(ServerHost, Host, From, Lang,
|
||||||
|
MaxRoomsDiscoItems, Node, RSM) of
|
||||||
{error, Err} ->
|
{error, Err} ->
|
||||||
xmpp:make_error(IQ, Err);
|
xmpp:make_error(IQ, Err);
|
||||||
{result, Result} ->
|
{result, Result} ->
|
||||||
|
@ -564,20 +622,22 @@ get_rooms(ServerHost, Host) ->
|
||||||
|
|
||||||
load_permanent_rooms(Host, ServerHost, Access,
|
load_permanent_rooms(Host, ServerHost, Access,
|
||||||
HistorySize, RoomShaper) ->
|
HistorySize, RoomShaper) ->
|
||||||
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun(R) ->
|
fun(R) ->
|
||||||
{Room, Host} = R#muc_room.name_host,
|
{Room, Host} = R#muc_room.name_host,
|
||||||
case mnesia:dirty_read(muc_online_room, {Room, Host}) of
|
case RMod:find_online_room(Room, Host) of
|
||||||
[] ->
|
error ->
|
||||||
{ok, Pid} = mod_muc_room:start(Host,
|
{ok, Pid} = mod_muc_room:start(Host,
|
||||||
ServerHost, Access, Room,
|
ServerHost, Access, Room,
|
||||||
HistorySize, RoomShaper,
|
HistorySize, RoomShaper,
|
||||||
R#muc_room.opts),
|
R#muc_room.opts),
|
||||||
register_room(Host, Room, Pid);
|
RMod:register_online_room(Room, Host, Pid);
|
||||||
_ -> ok
|
{ok, _} ->
|
||||||
end
|
ok
|
||||||
end,
|
end
|
||||||
get_rooms(ServerHost, Host)).
|
end,
|
||||||
|
get_rooms(ServerHost, Host)).
|
||||||
|
|
||||||
start_new_room(Host, ServerHost, Access, Room,
|
start_new_room(Host, ServerHost, Access, Room,
|
||||||
HistorySize, RoomShaper, From,
|
HistorySize, RoomShaper, From,
|
||||||
|
@ -594,19 +654,12 @@ start_new_room(Host, ServerHost, Access, Room,
|
||||||
HistorySize, RoomShaper, Opts)
|
HistorySize, RoomShaper, Opts)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
register_room(Host, Room, Pid) ->
|
-spec iq_disco_items(binary(), binary(), jid(), binary(), integer(), binary(),
|
||||||
F = fun() ->
|
|
||||||
mnesia:write(#muc_online_room{name_host = {Room, Host},
|
|
||||||
pid = Pid})
|
|
||||||
end,
|
|
||||||
mnesia:transaction(F).
|
|
||||||
|
|
||||||
-spec iq_disco_items(binary(), jid(), binary(), integer(), binary(),
|
|
||||||
rsm_set() | undefined) ->
|
rsm_set() | undefined) ->
|
||||||
{result, disco_items()} | {error, stanza_error()}.
|
{result, disco_items()} | {error, stanza_error()}.
|
||||||
iq_disco_items(Host, From, Lang, MaxRoomsDiscoItems, Node, RSM)
|
iq_disco_items(ServerHost, Host, From, Lang, MaxRoomsDiscoItems, Node, RSM)
|
||||||
when Node == <<"">>; Node == <<"nonemptyrooms">>; Node == <<"emptyrooms">> ->
|
when Node == <<"">>; Node == <<"nonemptyrooms">>; Node == <<"emptyrooms">> ->
|
||||||
Count = get_vh_rooms_count(Host),
|
Count = count_online_rooms(ServerHost, Host),
|
||||||
Query = if Node == <<"">>, RSM == undefined, Count > MaxRoomsDiscoItems ->
|
Query = if Node == <<"">>, RSM == undefined, Count > MaxRoomsDiscoItems ->
|
||||||
{get_disco_item, only_non_empty, From, Lang};
|
{get_disco_item, only_non_empty, From, Lang};
|
||||||
Node == <<"nonemptyrooms">> ->
|
Node == <<"nonemptyrooms">> ->
|
||||||
|
@ -616,7 +669,13 @@ iq_disco_items(Host, From, Lang, MaxRoomsDiscoItems, Node, RSM)
|
||||||
true ->
|
true ->
|
||||||
{get_disco_item, all, From, Lang}
|
{get_disco_item, all, From, Lang}
|
||||||
end,
|
end,
|
||||||
Items = get_vh_rooms(Host, Query, RSM),
|
Items = lists:flatmap(
|
||||||
|
fun(R) ->
|
||||||
|
case get_room_disco_item(R, Query) of
|
||||||
|
{ok, Item} -> [Item];
|
||||||
|
{error, _} -> []
|
||||||
|
end
|
||||||
|
end, get_online_rooms(ServerHost, Host, RSM)),
|
||||||
ResRSM = case Items of
|
ResRSM = case Items of
|
||||||
[_|_] when RSM /= undefined ->
|
[_|_] when RSM /= undefined ->
|
||||||
#disco_item{jid = #jid{luser = First}} = hd(Items),
|
#disco_item{jid = #jid{luser = First}} = hd(Items),
|
||||||
|
@ -630,89 +689,30 @@ iq_disco_items(Host, From, Lang, MaxRoomsDiscoItems, Node, RSM)
|
||||||
undefined
|
undefined
|
||||||
end,
|
end,
|
||||||
{result, #disco_items{node = Node, items = Items, rsm = ResRSM}};
|
{result, #disco_items{node = Node, items = Items, rsm = ResRSM}};
|
||||||
iq_disco_items(_Host, _From, Lang, _MaxRoomsDiscoItems, _Node, _RSM) ->
|
iq_disco_items(_ServerHost, _Host, _From, Lang, _MaxRoomsDiscoItems, _Node, _RSM) ->
|
||||||
{error, xmpp:err_item_not_found(<<"Node not found">>, Lang)}.
|
{error, xmpp:err_item_not_found(<<"Node not found">>, Lang)}.
|
||||||
|
|
||||||
-spec get_vh_rooms(binary, term(), rsm_set() | undefined) -> [disco_item()].
|
-spec get_room_disco_item({binary(), binary(), pid()},
|
||||||
get_vh_rooms(Host, Query,
|
term()) -> {ok, disco_item()} |
|
||||||
#rsm_set{max = Max, 'after' = After, before = undefined})
|
{error, timeout | notfound}.
|
||||||
when is_binary(After), After /= <<"">> ->
|
get_room_disco_item({Name, Host, Pid}, Query) ->
|
||||||
lists:reverse(get_vh_rooms(next, {After, Host}, Host, Query, 0, Max, []));
|
RoomJID = jid:make(Name, Host),
|
||||||
get_vh_rooms(Host, Query,
|
try gen_fsm:sync_send_all_state_event(Pid, Query, 100) of
|
||||||
#rsm_set{max = Max, 'after' = undefined, before = Before})
|
{item, Desc} ->
|
||||||
when is_binary(Before), Before /= <<"">> ->
|
{ok, #disco_item{jid = RoomJID, name = Desc}};
|
||||||
get_vh_rooms(prev, {Before, Host}, Host, Query, 0, Max, []);
|
false ->
|
||||||
get_vh_rooms(Host, Query,
|
{error, notfound}
|
||||||
#rsm_set{max = Max, 'after' = undefined, before = <<"">>}) ->
|
catch _:{timeout, _} ->
|
||||||
get_vh_rooms(last, {<<"">>, Host}, Host, Query, 0, Max, []);
|
{error, timeout};
|
||||||
get_vh_rooms(Host, Query, #rsm_set{max = Max}) ->
|
_:{noproc, _} ->
|
||||||
lists:reverse(get_vh_rooms(first, {<<"">>, Host}, Host, Query, 0, Max, []));
|
|
||||||
get_vh_rooms(Host, Query, undefined) ->
|
|
||||||
lists:reverse(get_vh_rooms(first, {<<"">>, Host}, Host, Query, 0, undefined, [])).
|
|
||||||
|
|
||||||
-spec get_vh_rooms(prev | next | last | first,
|
|
||||||
{binary(), binary()}, binary(), term(),
|
|
||||||
non_neg_integer(), non_neg_integer() | undefined,
|
|
||||||
[disco_item()]) -> [disco_item()].
|
|
||||||
get_vh_rooms(_Action, _Key, _Host, _Query, Count, Max, Items) when Count >= Max ->
|
|
||||||
Items;
|
|
||||||
get_vh_rooms(Action, Key, Host, Query, Count, Max, Items) ->
|
|
||||||
Call = fun() ->
|
|
||||||
case Action of
|
|
||||||
prev -> mnesia:dirty_prev(muc_online_room, Key);
|
|
||||||
next -> mnesia:dirty_next(muc_online_room, Key);
|
|
||||||
last -> mnesia:dirty_last(muc_online_room);
|
|
||||||
first -> mnesia:dirty_first(muc_online_room)
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
NewAction = case Action of
|
|
||||||
last -> prev;
|
|
||||||
first -> next;
|
|
||||||
_ -> Action
|
|
||||||
end,
|
|
||||||
try Call() of
|
|
||||||
'$end_of_table' ->
|
|
||||||
Items;
|
|
||||||
{_, Host} = NewKey ->
|
|
||||||
case get_room_disco_item(NewKey, Query) of
|
|
||||||
{ok, Item} ->
|
|
||||||
get_vh_rooms(NewAction, NewKey, Host, Query,
|
|
||||||
Count + 1, Max, [Item|Items]);
|
|
||||||
{error, _} ->
|
|
||||||
get_vh_rooms(NewAction, NewKey, Host, Query,
|
|
||||||
Count, Max, Items)
|
|
||||||
end;
|
|
||||||
NewKey ->
|
|
||||||
get_vh_rooms(NewAction, NewKey, Host, Query, Count, Max, Items)
|
|
||||||
catch _:{aborted, {badarg, _}} ->
|
|
||||||
Items
|
|
||||||
end.
|
|
||||||
|
|
||||||
-spec get_room_disco_item({binary(), binary()}, term()) -> {ok, disco_item()} |
|
|
||||||
{error, timeout | notfound}.
|
|
||||||
get_room_disco_item({Name, Host}, Query) ->
|
|
||||||
case mnesia:dirty_read(muc_online_room, {Name, Host}) of
|
|
||||||
[#muc_online_room{pid = Pid}|_] ->
|
|
||||||
RoomJID = jid:make(Name, Host),
|
|
||||||
try gen_fsm:sync_send_all_state_event(Pid, Query, 100) of
|
|
||||||
{item, Desc} ->
|
|
||||||
{ok, #disco_item{jid = RoomJID, name = Desc}};
|
|
||||||
false ->
|
|
||||||
{error, notfound}
|
|
||||||
catch _:{timeout, _} ->
|
|
||||||
{error, timeout};
|
|
||||||
_:{noproc, _} ->
|
|
||||||
{error, notfound}
|
|
||||||
end;
|
|
||||||
_ ->
|
|
||||||
{error, notfound}
|
{error, notfound}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_subscribed_rooms(_ServerHost, Host, From) ->
|
get_subscribed_rooms(ServerHost, Host, From) ->
|
||||||
Rooms = get_vh_rooms(Host),
|
Rooms = get_online_rooms(ServerHost, Host),
|
||||||
BareFrom = jid:remove_resource(From),
|
BareFrom = jid:remove_resource(From),
|
||||||
lists:flatmap(
|
lists:flatmap(
|
||||||
fun(#muc_online_room{name_host = {Name, _}, pid = Pid}) ->
|
fun({Name, _, Pid}) ->
|
||||||
case gen_fsm:sync_send_all_state_event(Pid, {is_subscribed, BareFrom}) of
|
case gen_fsm:sync_send_all_state_event(Pid, {is_subscribed, BareFrom}) of
|
||||||
true -> [jid:make(Name, Host)];
|
true -> [jid:make(Name, Host)];
|
||||||
false -> []
|
false -> []
|
||||||
|
@ -793,72 +793,28 @@ process_iq_register_set(ServerHost, Host, From,
|
||||||
{error, xmpp:err_not_acceptable(ErrText, Lang)}
|
{error, xmpp:err_not_acceptable(ErrText, Lang)}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
broadcast_service_message(Host, Msg) ->
|
-spec broadcast_service_message(binary(), binary(), message()) -> ok.
|
||||||
|
broadcast_service_message(ServerHost, Host, Msg) ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun(#muc_online_room{pid = Pid}) ->
|
fun({_, _, Pid}) ->
|
||||||
gen_fsm:send_all_state_event(
|
gen_fsm:send_all_state_event(
|
||||||
Pid, {service_message, Msg})
|
Pid, {service_message, Msg})
|
||||||
end, get_vh_rooms(Host)).
|
end, get_online_rooms(ServerHost, Host)).
|
||||||
|
|
||||||
|
-spec get_online_rooms(binary(), binary()) -> [{binary(), binary(), pid()}].
|
||||||
|
get_online_rooms(ServerHost, Host) ->
|
||||||
|
get_online_rooms(ServerHost, Host, undefined).
|
||||||
|
|
||||||
get_vh_rooms(Host) ->
|
-spec get_online_rooms(binary(), binary(), undefined | rsm_set()) ->
|
||||||
mnesia:dirty_select(muc_online_room,
|
[{binary(), binary(), pid()}].
|
||||||
[{#muc_online_room{name_host = '$1', _ = '_'},
|
get_online_rooms(ServerHost, Host, RSM) ->
|
||||||
[{'==', {element, 2, '$1'}, Host}],
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
['$_']}]).
|
RMod:get_online_rooms(Host, RSM).
|
||||||
|
|
||||||
-spec get_vh_rooms_count(binary()) -> non_neg_integer().
|
-spec count_online_rooms(binary(), binary()) -> non_neg_integer().
|
||||||
get_vh_rooms_count(Host) ->
|
count_online_rooms(ServerHost, Host) ->
|
||||||
ets:select_count(muc_online_room,
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
ets:fun2ms(
|
RMod:count_online_rooms(Host).
|
||||||
fun(#muc_online_room{name_host = {_, H}}) ->
|
|
||||||
H == Host
|
|
||||||
end)).
|
|
||||||
|
|
||||||
clean_table_from_bad_node(Node) ->
|
|
||||||
F = fun() ->
|
|
||||||
Es = mnesia:select(
|
|
||||||
muc_online_room,
|
|
||||||
[{#muc_online_room{pid = '$1', _ = '_'},
|
|
||||||
[{'==', {node, '$1'}, Node}],
|
|
||||||
['$_']}]),
|
|
||||||
lists:foreach(fun(E) ->
|
|
||||||
mnesia:delete_object(E)
|
|
||||||
end, Es)
|
|
||||||
end,
|
|
||||||
mnesia:async_dirty(F).
|
|
||||||
|
|
||||||
clean_table_from_bad_node(Node, Host) ->
|
|
||||||
F = fun() ->
|
|
||||||
Es = mnesia:select(
|
|
||||||
muc_online_room,
|
|
||||||
[{#muc_online_room{pid = '$1',
|
|
||||||
name_host = {'_', Host},
|
|
||||||
_ = '_'},
|
|
||||||
[{'==', {node, '$1'}, Node}],
|
|
||||||
['$_']}]),
|
|
||||||
lists:foreach(fun(E) ->
|
|
||||||
mnesia:delete_object(E)
|
|
||||||
end, Es)
|
|
||||||
end,
|
|
||||||
mnesia:async_dirty(F).
|
|
||||||
|
|
||||||
update_tables() ->
|
|
||||||
try
|
|
||||||
case mnesia:table_info(muc_online_room, type) of
|
|
||||||
ordered_set -> ok;
|
|
||||||
_ ->
|
|
||||||
case mnesia:delete_table(muc_online_room) of
|
|
||||||
{atomic, ok} -> ok;
|
|
||||||
Err -> erlang:error(Err)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
catch _:{aborted, {no_exists, muc_online_room}} -> ok;
|
|
||||||
_:{aborted, {no_exists, muc_online_room, type}} -> ok;
|
|
||||||
E:R ->
|
|
||||||
?ERROR_MSG("failed to update mnesia table '~s': ~p",
|
|
||||||
[muc_online_room, {E, R}])
|
|
||||||
end.
|
|
||||||
|
|
||||||
opts_to_binary(Opts) ->
|
opts_to_binary(Opts) ->
|
||||||
lists:map(
|
lists:map(
|
||||||
|
@ -922,6 +878,7 @@ mod_opt_type(access_create) ->
|
||||||
mod_opt_type(access_persistent) ->
|
mod_opt_type(access_persistent) ->
|
||||||
fun acl:access_rules_validator/1;
|
fun acl:access_rules_validator/1;
|
||||||
mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
||||||
|
mod_opt_type(ram_db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
||||||
mod_opt_type(default_room_options) ->
|
mod_opt_type(default_room_options) ->
|
||||||
fun (L) when is_list(L) -> L end;
|
fun (L) when is_list(L) -> L end;
|
||||||
mod_opt_type(history_size) ->
|
mod_opt_type(history_size) ->
|
||||||
|
@ -963,7 +920,7 @@ mod_opt_type(user_presence_shaper) ->
|
||||||
fun (A) when is_atom(A) -> A end;
|
fun (A) when is_atom(A) -> A end;
|
||||||
mod_opt_type(_) ->
|
mod_opt_type(_) ->
|
||||||
[access, access_admin, access_create, access_persistent,
|
[access, access_admin, access_create, access_persistent,
|
||||||
db_type, default_room_options, history_size, host,
|
db_type, ram_db_type, default_room_options, history_size, host,
|
||||||
max_room_desc, max_room_id, max_room_name,
|
max_room_desc, max_room_id, max_room_name,
|
||||||
max_rooms_discoitems, max_user_conferences, max_users,
|
max_rooms_discoitems, max_user_conferences, max_users,
|
||||||
max_users_admin_threshold, max_users_presence,
|
max_users_admin_threshold, max_users_presence,
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
-include("xmpp.hrl").
|
-include("xmpp.hrl").
|
||||||
-include("mod_muc_room.hrl").
|
-include("mod_muc_room.hrl").
|
||||||
-include("mod_muc.hrl").
|
|
||||||
-include("ejabberd_http.hrl").
|
-include("ejabberd_http.hrl").
|
||||||
-include("ejabberd_web_admin.hrl").
|
-include("ejabberd_web_admin.hrl").
|
||||||
-include("ejabberd_commands.hrl").
|
-include("ejabberd_commands.hrl").
|
||||||
|
@ -207,22 +206,12 @@ get_commands_spec() ->
|
||||||
%%%
|
%%%
|
||||||
|
|
||||||
muc_online_rooms(ServerHost) ->
|
muc_online_rooms(ServerHost) ->
|
||||||
MUCHost = find_host(ServerHost),
|
Hosts = find_hosts(ServerHost),
|
||||||
Rooms = ets:tab2list(muc_online_room),
|
lists:flatmap(
|
||||||
lists:foldl(
|
fun(Host) ->
|
||||||
fun(Room, Results) ->
|
[{<<Name/binary, "@", Host/binary>>}
|
||||||
{Roomname, Host} = Room#muc_online_room.name_host,
|
|| {Name, _, _} <- mod_muc:get_online_rooms(Host)]
|
||||||
case MUCHost of
|
end, Hosts).
|
||||||
global ->
|
|
||||||
[<<Roomname/binary, "@", Host/binary>> | Results];
|
|
||||||
Host ->
|
|
||||||
[<<Roomname/binary, "@", Host/binary>> | Results];
|
|
||||||
_ ->
|
|
||||||
Results
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
[],
|
|
||||||
Rooms).
|
|
||||||
|
|
||||||
muc_unregister_nick(Nick) ->
|
muc_unregister_nick(Nick) ->
|
||||||
F2 = fun(N) ->
|
F2 = fun(N) ->
|
||||||
|
@ -237,14 +226,18 @@ muc_unregister_nick(Nick) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_user_rooms(LUser, LServer) ->
|
get_user_rooms(LUser, LServer) ->
|
||||||
US = {LUser, LServer},
|
lists:flatmap(
|
||||||
case catch ets:select(muc_online_users,
|
fun(ServerHost) ->
|
||||||
[{#muc_online_users{us = US, room='$1', host='$2', _ = '_'}, [], [{{'$1', '$2'}}]}])
|
case gen_mod:is_loaded(ServerHost, mod_muc) of
|
||||||
of
|
true ->
|
||||||
Res when is_list(Res) ->
|
Rooms = mod_muc:get_online_rooms_by_user(
|
||||||
[<<R/binary, "@", H/binary>> || {R, H} <- Res];
|
ServerHost, LUser, LServer),
|
||||||
_ -> []
|
[<<Name/binary, "@", Host/binary>>
|
||||||
end.
|
|| {Name, Host} <- Rooms];
|
||||||
|
false ->
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end, ?MYHOSTS).
|
||||||
|
|
||||||
%%----------------------------
|
%%----------------------------
|
||||||
%% Ad-hoc commands
|
%% Ad-hoc commands
|
||||||
|
@ -274,10 +267,14 @@ web_menu_host(Acc, _Host, Lang) ->
|
||||||
])).
|
])).
|
||||||
|
|
||||||
web_page_main(_, #request{path=[<<"muc">>], lang = Lang} = _Request) ->
|
web_page_main(_, #request{path=[<<"muc">>], lang = Lang} = _Request) ->
|
||||||
|
OnlineRoomsNumber = lists:foldl(
|
||||||
|
fun(Host, Acc) ->
|
||||||
|
Acc ++ mod_muc:count_online_rooms(Host)
|
||||||
|
end, 0, find_hosts(global)),
|
||||||
Res = [?XCT(<<"h1">>, <<"Multi-User Chat">>),
|
Res = [?XCT(<<"h1">>, <<"Multi-User Chat">>),
|
||||||
?XCT(<<"h3">>, <<"Statistics">>),
|
?XCT(<<"h3">>, <<"Statistics">>),
|
||||||
?XAE(<<"table">>, [],
|
?XAE(<<"table">>, [],
|
||||||
[?XE(<<"tbody">>, [?TDTD(<<"Total rooms">>, ets:info(muc_online_room, size)),
|
[?XE(<<"tbody">>, [?TDTD(<<"Total rooms">>, OnlineRoomsNumber),
|
||||||
?TDTD(<<"Permanent rooms">>, mnesia:table_info(muc_room, size)),
|
?TDTD(<<"Permanent rooms">>, mnesia:table_info(muc_room, size)),
|
||||||
?TDTD(<<"Registered nicknames">>, mnesia:table_info(muc_registered, size))
|
?TDTD(<<"Registered nicknames">>, mnesia:table_info(muc_registered, size))
|
||||||
])
|
])
|
||||||
|
@ -456,8 +453,8 @@ create_room_with_opts(Name1, Host1, ServerHost, CustomRoomOpts) ->
|
||||||
RoomShaper = gen_mod:get_module_opt(ServerHost, mod_muc, room_shaper, fun(X) -> X end, none),
|
RoomShaper = gen_mod:get_module_opt(ServerHost, mod_muc, room_shaper, fun(X) -> X end, none),
|
||||||
|
|
||||||
%% If the room does not exist yet in the muc_online_room
|
%% If the room does not exist yet in the muc_online_room
|
||||||
case mnesia:dirty_read(muc_online_room, {Name, Host}) of
|
case mod_muc:find_online_room(Name, Host) of
|
||||||
[] ->
|
error ->
|
||||||
%% Start the room
|
%% Start the room
|
||||||
{ok, Pid} = mod_muc_room:start(
|
{ok, Pid} = mod_muc_room:start(
|
||||||
Host,
|
Host,
|
||||||
|
@ -467,19 +464,12 @@ create_room_with_opts(Name1, Host1, ServerHost, CustomRoomOpts) ->
|
||||||
HistorySize,
|
HistorySize,
|
||||||
RoomShaper,
|
RoomShaper,
|
||||||
RoomOpts),
|
RoomOpts),
|
||||||
{atomic, ok} = register_room(Host, Name, Pid),
|
mod_muc:register_online_room(Host, Name, Pid),
|
||||||
ok;
|
ok;
|
||||||
_ ->
|
{ok, _} ->
|
||||||
error
|
error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
register_room(Host, Name, Pid) ->
|
|
||||||
F = fun() ->
|
|
||||||
mnesia:write(#muc_online_room{name_host = {Name, Host},
|
|
||||||
pid = Pid})
|
|
||||||
end,
|
|
||||||
mnesia:transaction(F).
|
|
||||||
|
|
||||||
%% Create the room only in the database.
|
%% Create the room only in the database.
|
||||||
%% It is required to restart the MUC service for the room to appear.
|
%% It is required to restart the MUC service for the room to appear.
|
||||||
muc_create_room(ServerHost, {Name, Host, _}, DefRoomOpts) ->
|
muc_create_room(ServerHost, {Name, Host, _}, DefRoomOpts) ->
|
||||||
|
@ -492,12 +482,11 @@ muc_create_room(ServerHost, {Name, Host, _}, DefRoomOpts) ->
|
||||||
%% If the room has participants, they are not notified that the room was destroyed;
|
%% 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.
|
%% they will notice when they try to chat and receive an error that the room doesn't exist.
|
||||||
destroy_room(Name, Service) ->
|
destroy_room(Name, Service) ->
|
||||||
case mnesia:dirty_read(muc_online_room, {Name, Service}) of
|
case mod_muc:find_online_room(Name, Service) of
|
||||||
[R] ->
|
{ok, Pid} ->
|
||||||
Pid = R#muc_online_room.pid,
|
|
||||||
gen_fsm:send_all_state_event(Pid, destroy),
|
gen_fsm:send_all_state_event(Pid, destroy),
|
||||||
ok;
|
ok;
|
||||||
[] ->
|
error ->
|
||||||
error
|
error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -602,19 +591,12 @@ muc_unused2(Action, ServerHost, Host, Last_allowed) ->
|
||||||
%%---------------
|
%%---------------
|
||||||
%% Get info
|
%% Get info
|
||||||
|
|
||||||
get_rooms(Host) ->
|
get_rooms(ServerHost) ->
|
||||||
Get_room_names = fun(Room_reg, Names) ->
|
Hosts = find_hosts(ServerHost),
|
||||||
Pid = Room_reg#muc_online_room.pid,
|
lists:flatmap(
|
||||||
case {Host, Room_reg#muc_online_room.name_host} of
|
fun(Host) ->
|
||||||
{Host, {Name1, Host}} ->
|
mod_muc:get_online_rooms(Host)
|
||||||
[{Name1, Host, Pid} | Names];
|
end, Hosts).
|
||||||
{global, {Name1, Host1}} ->
|
|
||||||
[{Name1, Host1, Pid} | Names];
|
|
||||||
_ ->
|
|
||||||
Names
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
ets:foldr(Get_room_names, [], muc_online_room).
|
|
||||||
|
|
||||||
get_room_config(Room_pid) ->
|
get_room_config(Room_pid) ->
|
||||||
{ok, R} = gen_fsm:sync_send_all_state_event(Room_pid, get_config),
|
{ok, R} = gen_fsm:sync_send_all_state_event(Room_pid, get_config),
|
||||||
|
@ -813,11 +795,11 @@ format_room_option(OptionString, ValueString) ->
|
||||||
|
|
||||||
%% @doc Get the Pid of an existing MUC room, or 'room_not_found'.
|
%% @doc Get the Pid of an existing MUC room, or 'room_not_found'.
|
||||||
get_room_pid(Name, Service) ->
|
get_room_pid(Name, Service) ->
|
||||||
case mnesia:dirty_read(muc_online_room, {Name, Service}) of
|
case mod_muc:find_online_room(Name, Service) of
|
||||||
[] ->
|
error ->
|
||||||
room_not_found;
|
room_not_found;
|
||||||
[Room] ->
|
{ok, Pid} ->
|
||||||
Room#muc_online_room.pid
|
Pid
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% It is required to put explicitely all the options because
|
%% It is required to put explicitely all the options because
|
||||||
|
@ -884,10 +866,9 @@ get_options(Config) ->
|
||||||
%% [{JID::string(), Domain::string(), Role::string(), Reason::string()}]
|
%% [{JID::string(), Domain::string(), Role::string(), Reason::string()}]
|
||||||
%% @doc Get the affiliations of the room Name@Service.
|
%% @doc Get the affiliations of the room Name@Service.
|
||||||
get_room_affiliations(Name, Service) ->
|
get_room_affiliations(Name, Service) ->
|
||||||
case mnesia:dirty_read(muc_online_room, {Name, Service}) of
|
case mod_muc:find_online_room(Name, Service) of
|
||||||
[R] ->
|
{ok, Pid} ->
|
||||||
%% Get the PID of the online room, then request its state
|
%% Get the PID of the online room, then request its state
|
||||||
Pid = R#muc_online_room.pid,
|
|
||||||
{ok, StateData} = gen_fsm:sync_send_all_state_event(Pid, get_state),
|
{ok, StateData} = gen_fsm:sync_send_all_state_event(Pid, get_state),
|
||||||
Affiliations = ?DICT:to_list(StateData#state.affiliations),
|
Affiliations = ?DICT:to_list(StateData#state.affiliations),
|
||||||
lists:map(
|
lists:map(
|
||||||
|
@ -896,7 +877,7 @@ get_room_affiliations(Name, Service) ->
|
||||||
({{Uname, Domain, _Res}, Aff}) when is_atom(Aff)->
|
({{Uname, Domain, _Res}, Aff}) when is_atom(Aff)->
|
||||||
{Uname, Domain, Aff, <<>>}
|
{Uname, Domain, Aff, <<>>}
|
||||||
end, Affiliations);
|
end, Affiliations);
|
||||||
[] ->
|
error ->
|
||||||
throw({error, "The room does not exist."})
|
throw({error, "The room does not exist."})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -914,14 +895,13 @@ get_room_affiliations(Name, Service) ->
|
||||||
%% In any other case the action will be to create the affiliation.
|
%% In any other case the action will be to create the affiliation.
|
||||||
set_room_affiliation(Name, Service, JID, AffiliationString) ->
|
set_room_affiliation(Name, Service, JID, AffiliationString) ->
|
||||||
Affiliation = jlib:binary_to_atom(AffiliationString),
|
Affiliation = jlib:binary_to_atom(AffiliationString),
|
||||||
case mnesia:dirty_read(muc_online_room, {Name, Service}) of
|
case mod_muc:find_online_room(Name, Service) of
|
||||||
[R] ->
|
{ok, Pid} ->
|
||||||
%% Get the PID for the online room so we can get the state of the room
|
%% 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, {jid:from_string(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)),
|
mod_muc:store_room(StateData#state.server_host, StateData#state.host, StateData#state.room, make_opts(StateData)),
|
||||||
ok;
|
ok;
|
||||||
[] ->
|
error ->
|
||||||
error
|
error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -1045,4 +1025,28 @@ find_host(ServerHost) when is_list(ServerHost) ->
|
||||||
find_host(ServerHost) ->
|
find_host(ServerHost) ->
|
||||||
gen_mod:get_module_opt_host(ServerHost, mod_muc, <<"conference.@HOST@">>).
|
gen_mod:get_module_opt_host(ServerHost, mod_muc, <<"conference.@HOST@">>).
|
||||||
|
|
||||||
|
find_hosts(Global) when Global == global;
|
||||||
|
Global == "global";
|
||||||
|
Global == <<"global">> ->
|
||||||
|
lists:flatmap(
|
||||||
|
fun(ServerHost) ->
|
||||||
|
case gen_mod:is_loaded(ServerHost, mod_muc) of
|
||||||
|
true ->
|
||||||
|
[gen_mod:get_module_opt_host(
|
||||||
|
ServerHost, mod_muc, <<"conference.@HOST@">>)];
|
||||||
|
false ->
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end, ?MYHOSTS);
|
||||||
|
find_hosts(ServerHost) when is_list(ServerHost) ->
|
||||||
|
find_hosts(list_to_binary(ServerHost));
|
||||||
|
find_hosts(ServerHost) ->
|
||||||
|
case gen_mod:is_loaded(ServerHost, mod_muc) of
|
||||||
|
true ->
|
||||||
|
[gen_mod:get_module_opt_host(
|
||||||
|
ServerHost, mod_muc, <<"conference.@HOST@">>)];
|
||||||
|
false ->
|
||||||
|
[]
|
||||||
|
end.
|
||||||
|
|
||||||
mod_opt_type(_) -> [].
|
mod_opt_type(_) -> [].
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
|
|
||||||
-include("xmpp.hrl").
|
-include("xmpp.hrl").
|
||||||
-include("mod_muc.hrl").
|
|
||||||
-include("mod_muc_room.hrl").
|
-include("mod_muc_room.hrl").
|
||||||
|
|
||||||
-define(T(Text), translate:translate(Lang, Text)).
|
-define(T(Text), translate:translate(Lang, Text)).
|
||||||
|
@ -1169,13 +1168,11 @@ get_room_occupants(RoomJIDString) ->
|
||||||
-spec get_room_state(binary(), binary()) -> mod_muc_room:state().
|
-spec get_room_state(binary(), binary()) -> mod_muc_room:state().
|
||||||
|
|
||||||
get_room_state(RoomName, MucService) ->
|
get_room_state(RoomName, MucService) ->
|
||||||
case mnesia:dirty_read(muc_online_room,
|
case mod_muc:find_online_room(RoomName, MucService) of
|
||||||
{RoomName, MucService})
|
{ok, RoomPid} ->
|
||||||
of
|
get_room_state(RoomPid);
|
||||||
[R] ->
|
error ->
|
||||||
RoomPid = R#muc_online_room.pid,
|
#state{}
|
||||||
get_room_state(RoomPid);
|
|
||||||
[] -> #state{}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec get_room_state(pid()) -> mod_muc_room:state().
|
-spec get_room_state(pid()) -> mod_muc_room:state().
|
||||||
|
|
|
@ -14,28 +14,55 @@
|
||||||
%% API
|
%% API
|
||||||
-export([init/2, import/3, store_room/4, restore_room/3, forget_room/3,
|
-export([init/2, import/3, store_room/4, restore_room/3, forget_room/3,
|
||||||
can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4]).
|
can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4]).
|
||||||
|
-export([register_online_room/3, unregister_online_room/3, find_online_room/2,
|
||||||
|
get_online_rooms/2, count_online_rooms/1, rsm_supported/0,
|
||||||
|
register_online_user/3, unregister_online_user/3,
|
||||||
|
count_online_rooms_by_user/2, get_online_rooms_by_user/2,
|
||||||
|
handle_event/1]).
|
||||||
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
|
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
|
||||||
get_affiliations/3, search_affiliation/4]).
|
get_affiliations/3, search_affiliation/4]).
|
||||||
|
|
||||||
-include("jid.hrl").
|
|
||||||
-include("mod_muc.hrl").
|
-include("mod_muc.hrl").
|
||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
|
-include("xmpp.hrl").
|
||||||
|
-include_lib("stdlib/include/ms_transform.hrl").
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, Opts) ->
|
init(Host, Opts) ->
|
||||||
MyHost = proplists:get_value(host, Opts),
|
MyHost = proplists:get_value(host, Opts),
|
||||||
ejabberd_mnesia:create(?MODULE, muc_room,
|
case gen_mod:db_mod(Host, Opts, mod_muc) of
|
||||||
[{disc_copies, [node()]},
|
?MODULE ->
|
||||||
{attributes,
|
ejabberd_mnesia:create(?MODULE, muc_room,
|
||||||
record_info(fields, muc_room)}]),
|
[{disc_copies, [node()]},
|
||||||
ejabberd_mnesia:create(?MODULE, muc_registered,
|
{attributes,
|
||||||
[{disc_copies, [node()]},
|
record_info(fields, muc_room)}]),
|
||||||
{attributes,
|
ejabberd_mnesia:create(?MODULE, muc_registered,
|
||||||
record_info(fields, muc_registered)}]),
|
[{disc_copies, [node()]},
|
||||||
update_tables(MyHost),
|
{attributes,
|
||||||
mnesia:add_table_index(muc_registered, nick).
|
record_info(fields, muc_registered)}]),
|
||||||
|
update_tables(MyHost),
|
||||||
|
mnesia:add_table_index(muc_registered, nick);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
case gen_mod:ram_db_mod(Host, Opts, mod_muc) of
|
||||||
|
?MODULE ->
|
||||||
|
update_muc_online_table(),
|
||||||
|
ejabberd_mnesia:create(?MODULE, muc_online_room,
|
||||||
|
[{ram_copies, [node()]},
|
||||||
|
{type, ordered_set},
|
||||||
|
{attributes,
|
||||||
|
record_info(fields, muc_online_room)}]),
|
||||||
|
mnesia:add_table_copy(muc_online_room, node(), ram_copies),
|
||||||
|
catch ets:new(muc_online_users,
|
||||||
|
[bag, named_table, public, {keypos, 2}]),
|
||||||
|
clean_table_from_bad_node(node(), MyHost),
|
||||||
|
mnesia:subscribe(system);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
store_room(_LServer, Host, Name, Opts) ->
|
store_room(_LServer, Host, Name, Opts) ->
|
||||||
F = fun () ->
|
F = fun () ->
|
||||||
|
@ -132,6 +159,128 @@ get_affiliations(_ServerHost, _Room, _Host) ->
|
||||||
search_affiliation(_ServerHost, _Room, _Host, _Affiliation) ->
|
search_affiliation(_ServerHost, _Room, _Host, _Affiliation) ->
|
||||||
{error, not_implemented}.
|
{error, not_implemented}.
|
||||||
|
|
||||||
|
register_online_room(Room, Host, Pid) ->
|
||||||
|
F = fun() ->
|
||||||
|
mnesia:write(
|
||||||
|
#muc_online_room{name_host = {Room, Host}, pid = Pid})
|
||||||
|
end,
|
||||||
|
mnesia:transaction(F).
|
||||||
|
|
||||||
|
unregister_online_room(Room, Host, Pid) ->
|
||||||
|
F = fun () ->
|
||||||
|
mnesia:delete_object(
|
||||||
|
#muc_online_room{name_host = {Room, Host}, pid = Pid})
|
||||||
|
end,
|
||||||
|
mnesia:transaction(F).
|
||||||
|
|
||||||
|
find_online_room(Room, Host) ->
|
||||||
|
case mnesia:dirty_read(muc_online_room, {Room, Host}) of
|
||||||
|
[] -> error;
|
||||||
|
[#muc_online_room{pid = Pid}] -> {ok, Pid}
|
||||||
|
end.
|
||||||
|
|
||||||
|
count_online_rooms(Host) ->
|
||||||
|
ets:select_count(
|
||||||
|
muc_online_room,
|
||||||
|
ets:fun2ms(
|
||||||
|
fun(#muc_online_room{name_host = {_, H}}) ->
|
||||||
|
H == Host
|
||||||
|
end)).
|
||||||
|
|
||||||
|
get_online_rooms(Host,
|
||||||
|
#rsm_set{max = Max, 'after' = After, before = undefined})
|
||||||
|
when is_binary(After), After /= <<"">> ->
|
||||||
|
lists:reverse(get_online_rooms(next, {After, Host}, Host, 0, Max, []));
|
||||||
|
get_online_rooms(Host,
|
||||||
|
#rsm_set{max = Max, 'after' = undefined, before = Before})
|
||||||
|
when is_binary(Before), Before /= <<"">> ->
|
||||||
|
get_online_rooms(prev, {Before, Host}, Host, 0, Max, []);
|
||||||
|
get_online_rooms(Host,
|
||||||
|
#rsm_set{max = Max, 'after' = undefined, before = <<"">>}) ->
|
||||||
|
get_online_rooms(last, {<<"">>, Host}, Host, 0, Max, []);
|
||||||
|
get_online_rooms(Host, #rsm_set{max = Max}) ->
|
||||||
|
lists:reverse(get_online_rooms(first, {<<"">>, Host}, Host, 0, Max, []));
|
||||||
|
get_online_rooms(Host, undefined) ->
|
||||||
|
mnesia:dirty_select(
|
||||||
|
muc_online_room,
|
||||||
|
ets:fun2ms(
|
||||||
|
fun(#muc_online_room{name_host = {Name, H}, pid = Pid})
|
||||||
|
when H == Host -> {Name, Host, Pid}
|
||||||
|
end)).
|
||||||
|
|
||||||
|
-spec get_online_rooms(prev | next | last | first,
|
||||||
|
{binary(), binary()}, binary(),
|
||||||
|
non_neg_integer(), non_neg_integer() | undefined,
|
||||||
|
[{binary(), binary(), pid()}]) ->
|
||||||
|
[{binary(), binary(), pid()}].
|
||||||
|
get_online_rooms(_Action, _Key, _Host, Count, Max, Items) when Count >= Max ->
|
||||||
|
Items;
|
||||||
|
get_online_rooms(Action, Key, Host, Count, Max, Items) ->
|
||||||
|
Call = fun() ->
|
||||||
|
case Action of
|
||||||
|
prev -> mnesia:dirty_prev(muc_online_room, Key);
|
||||||
|
next -> mnesia:dirty_next(muc_online_room, Key);
|
||||||
|
last -> mnesia:dirty_last(muc_online_room);
|
||||||
|
first -> mnesia:dirty_first(muc_online_room)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
NewAction = case Action of
|
||||||
|
last -> prev;
|
||||||
|
first -> next;
|
||||||
|
_ -> Action
|
||||||
|
end,
|
||||||
|
try Call() of
|
||||||
|
'$end_of_table' ->
|
||||||
|
Items;
|
||||||
|
{Room, Host} = NewKey ->
|
||||||
|
case find_online_room(Room, Host) of
|
||||||
|
{ok, Pid} ->
|
||||||
|
get_online_rooms(NewAction, NewKey, Host,
|
||||||
|
Count + 1, Max, [{Room, Host, Pid}|Items]);
|
||||||
|
{error, _} ->
|
||||||
|
get_online_rooms(NewAction, NewKey, Host,
|
||||||
|
Count, Max, Items)
|
||||||
|
end;
|
||||||
|
NewKey ->
|
||||||
|
get_online_rooms(NewAction, NewKey, Host, Count, Max, Items)
|
||||||
|
catch _:{aborted, {badarg, _}} ->
|
||||||
|
Items
|
||||||
|
end.
|
||||||
|
|
||||||
|
handle_event({mnesia_system_event, {mnesia_down, Node}}) ->
|
||||||
|
clean_table_from_bad_node(Node);
|
||||||
|
handle_event(_) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
rsm_supported() ->
|
||||||
|
true.
|
||||||
|
|
||||||
|
register_online_user({U, S, R}, Room, Host) ->
|
||||||
|
ets:insert(muc_online_users,
|
||||||
|
#muc_online_users{us = {U, S}, resource = R,
|
||||||
|
room = Room, host = Host}).
|
||||||
|
|
||||||
|
unregister_online_user({U, S, R}, Room, Host) ->
|
||||||
|
ets:delete_object(muc_online_users,
|
||||||
|
#muc_online_users{us = {U, S}, resource = R,
|
||||||
|
room = Room, host = Host}).
|
||||||
|
|
||||||
|
count_online_rooms_by_user(U, S) ->
|
||||||
|
ets:select_count(
|
||||||
|
muc_online_users,
|
||||||
|
ets:fun2ms(
|
||||||
|
fun(#muc_online_users{us = {U1, S1}}) ->
|
||||||
|
U == U1 andalso S == S1
|
||||||
|
end)).
|
||||||
|
|
||||||
|
get_online_rooms_by_user(U, S) ->
|
||||||
|
ets:select(
|
||||||
|
muc_online_users,
|
||||||
|
ets:fun2ms(
|
||||||
|
fun(#muc_online_users{us = {U1, S1}, room = Room, host = Host})
|
||||||
|
when U == U1 andalso S == S1 -> {Room, Host}
|
||||||
|
end)).
|
||||||
|
|
||||||
import(_LServer, <<"muc_room">>,
|
import(_LServer, <<"muc_room">>,
|
||||||
[Name, RoomHost, SOpts, _TimeStamp]) ->
|
[Name, RoomHost, SOpts, _TimeStamp]) ->
|
||||||
Opts = mod_muc:opts_to_binary(ejabberd_sql:decode_term(SOpts)),
|
Opts = mod_muc:opts_to_binary(ejabberd_sql:decode_term(SOpts)),
|
||||||
|
@ -148,6 +297,34 @@ import(_LServer, <<"muc_registered">>,
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
clean_table_from_bad_node(Node) ->
|
||||||
|
F = fun() ->
|
||||||
|
Es = mnesia:select(
|
||||||
|
muc_online_room,
|
||||||
|
[{#muc_online_room{pid = '$1', _ = '_'},
|
||||||
|
[{'==', {node, '$1'}, Node}],
|
||||||
|
['$_']}]),
|
||||||
|
lists:foreach(fun(E) ->
|
||||||
|
mnesia:delete_object(E)
|
||||||
|
end, Es)
|
||||||
|
end,
|
||||||
|
mnesia:async_dirty(F).
|
||||||
|
|
||||||
|
clean_table_from_bad_node(Node, Host) ->
|
||||||
|
F = fun() ->
|
||||||
|
Es = mnesia:select(
|
||||||
|
muc_online_room,
|
||||||
|
[{#muc_online_room{pid = '$1',
|
||||||
|
name_host = {'_', Host},
|
||||||
|
_ = '_'},
|
||||||
|
[{'==', {node, '$1'}, Node}],
|
||||||
|
['$_']}]),
|
||||||
|
lists:foreach(fun(E) ->
|
||||||
|
mnesia:delete_object(E)
|
||||||
|
end, Es)
|
||||||
|
end,
|
||||||
|
mnesia:async_dirty(F).
|
||||||
|
|
||||||
update_tables(Host) ->
|
update_tables(Host) ->
|
||||||
update_muc_room_table(Host),
|
update_muc_room_table(Host),
|
||||||
update_muc_registered_table(Host).
|
update_muc_registered_table(Host).
|
||||||
|
@ -188,3 +365,20 @@ update_muc_registered_table(_Host) ->
|
||||||
?INFO_MSG("Recreating muc_registered table", []),
|
?INFO_MSG("Recreating muc_registered table", []),
|
||||||
mnesia:transform_table(muc_registered, ignore, Fields)
|
mnesia:transform_table(muc_registered, ignore, Fields)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
update_muc_online_table() ->
|
||||||
|
try
|
||||||
|
case mnesia:table_info(muc_online_room, type) of
|
||||||
|
ordered_set -> ok;
|
||||||
|
_ ->
|
||||||
|
case mnesia:delete_table(muc_online_room) of
|
||||||
|
{atomic, ok} -> ok;
|
||||||
|
Err -> erlang:error(Err)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
catch _:{aborted, {no_exists, muc_online_room}} -> ok;
|
||||||
|
_:{aborted, {no_exists, muc_online_room, type}} -> ok;
|
||||||
|
E:R ->
|
||||||
|
?ERROR_MSG("failed to update mnesia table '~s': ~p",
|
||||||
|
[muc_online_room, {E, R, erlang:get_stacktrace()}])
|
||||||
|
end.
|
||||||
|
|
|
@ -14,6 +14,11 @@
|
||||||
%% API
|
%% API
|
||||||
-export([init/2, import/3, store_room/4, restore_room/3, forget_room/3,
|
-export([init/2, import/3, store_room/4, restore_room/3, forget_room/3,
|
||||||
can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4]).
|
can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4]).
|
||||||
|
-export([register_online_room/3, unregister_online_room/3, find_online_room/2,
|
||||||
|
get_online_rooms/2, count_online_rooms/1, rsm_supported/0,
|
||||||
|
register_online_user/3, unregister_online_user/3,
|
||||||
|
count_online_rooms_by_user/2, get_online_rooms_by_user/2,
|
||||||
|
handle_event/1]).
|
||||||
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
|
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
|
||||||
get_affiliations/3, search_affiliation/4]).
|
get_affiliations/3, search_affiliation/4]).
|
||||||
|
|
||||||
|
@ -120,6 +125,39 @@ get_affiliations(_ServerHost, _Room, _Host) ->
|
||||||
search_affiliation(_ServerHost, _Room, _Host, _Affiliation) ->
|
search_affiliation(_ServerHost, _Room, _Host, _Affiliation) ->
|
||||||
{error, not_implemented}.
|
{error, not_implemented}.
|
||||||
|
|
||||||
|
register_online_room(_, _, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
unregister_online_room(_, _, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
find_online_room(_, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
count_online_rooms(_) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
get_online_rooms(_, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
handle_event(_) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
rsm_supported() ->
|
||||||
|
false.
|
||||||
|
|
||||||
|
register_online_user(_, _, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
unregister_online_user(_, _, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
count_online_rooms_by_user(_, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
get_online_rooms_by_user(_, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
import(_LServer, <<"muc_room">>,
|
import(_LServer, <<"muc_room">>,
|
||||||
[Name, RoomHost, SOpts, _TimeStamp]) ->
|
[Name, RoomHost, SOpts, _TimeStamp]) ->
|
||||||
Opts = mod_muc:opts_to_binary(ejabberd_sql:decode_term(SOpts)),
|
Opts = mod_muc:opts_to_binary(ejabberd_sql:decode_term(SOpts)),
|
||||||
|
|
|
@ -1798,7 +1798,7 @@ add_new_user(From, Nick, Packet, StateData) ->
|
||||||
Affiliation = get_affiliation(From, StateData),
|
Affiliation = get_affiliation(From, StateData),
|
||||||
ServiceAffiliation = get_service_affiliation(From,
|
ServiceAffiliation = get_service_affiliation(From,
|
||||||
StateData),
|
StateData),
|
||||||
NConferences = tab_count_user(From),
|
NConferences = tab_count_user(From, StateData),
|
||||||
MaxConferences =
|
MaxConferences =
|
||||||
gen_mod:get_module_opt(StateData#state.server_host,
|
gen_mod:get_module_opt(StateData#state.server_host,
|
||||||
mod_muc, max_user_conferences,
|
mod_muc, max_user_conferences,
|
||||||
|
@ -3968,38 +3968,25 @@ add_to_log(Type, Data, StateData) ->
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
%% Users number checking
|
%% Users number checking
|
||||||
|
|
||||||
-spec tab_add_online_user(jid(), state()) -> ok.
|
-spec tab_add_online_user(jid(), state()) -> any().
|
||||||
tab_add_online_user(JID, StateData) ->
|
tab_add_online_user(JID, StateData) ->
|
||||||
{LUser, LServer, LResource} = jid:tolower(JID),
|
|
||||||
US = {LUser, LServer},
|
|
||||||
Room = StateData#state.room,
|
Room = StateData#state.room,
|
||||||
Host = StateData#state.host,
|
Host = StateData#state.host,
|
||||||
catch ets:insert(muc_online_users,
|
ServerHost = StateData#state.server_host,
|
||||||
#muc_online_users{us = US, resource = LResource,
|
mod_muc:register_online_user(ServerHost, jid:tolower(JID), Room, Host).
|
||||||
room = Room, host = Host}),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
-spec tab_remove_online_user(jid(), state()) -> ok.
|
-spec tab_remove_online_user(jid(), state()) -> any().
|
||||||
tab_remove_online_user(JID, StateData) ->
|
tab_remove_online_user(JID, StateData) ->
|
||||||
{LUser, LServer, LResource} = jid:tolower(JID),
|
|
||||||
US = {LUser, LServer},
|
|
||||||
Room = StateData#state.room,
|
Room = StateData#state.room,
|
||||||
Host = StateData#state.host,
|
Host = StateData#state.host,
|
||||||
catch ets:delete_object(muc_online_users,
|
ServerHost = StateData#state.server_host,
|
||||||
#muc_online_users{us = US, resource = LResource,
|
mod_muc:unregister_online_user(ServerHost, jid:tolower(JID), Room, Host).
|
||||||
room = Room, host = Host}),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
-spec tab_count_user(jid()) -> non_neg_integer().
|
-spec tab_count_user(jid(), state()) -> non_neg_integer().
|
||||||
tab_count_user(JID) ->
|
tab_count_user(JID, StateData) ->
|
||||||
|
ServerHost = StateData#state.server_host,
|
||||||
{LUser, LServer, _} = jid:tolower(JID),
|
{LUser, LServer, _} = jid:tolower(JID),
|
||||||
US = {LUser, LServer},
|
mod_muc:count_online_rooms_by_user(ServerHost, LUser, LServer).
|
||||||
case catch ets:select(muc_online_users,
|
|
||||||
[{#muc_online_users{us = US, _ = '_'}, [], [[]]}])
|
|
||||||
of
|
|
||||||
Res when is_list(Res) -> length(Res);
|
|
||||||
_ -> 0
|
|
||||||
end.
|
|
||||||
|
|
||||||
-spec element_size(stanza()) -> non_neg_integer().
|
-spec element_size(stanza()) -> non_neg_integer().
|
||||||
element_size(El) ->
|
element_size(El) ->
|
||||||
|
|
|
@ -17,6 +17,11 @@
|
||||||
-export([init/2, store_room/4, restore_room/3, forget_room/3,
|
-export([init/2, store_room/4, restore_room/3, forget_room/3,
|
||||||
can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4,
|
can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4,
|
||||||
import/3, export/1]).
|
import/3, export/1]).
|
||||||
|
-export([register_online_room/3, unregister_online_room/3, find_online_room/2,
|
||||||
|
get_online_rooms/2, count_online_rooms/1, rsm_supported/0,
|
||||||
|
register_online_user/3, unregister_online_user/3,
|
||||||
|
count_online_rooms_by_user/2, get_online_rooms_by_user/2,
|
||||||
|
handle_event/1]).
|
||||||
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
|
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
|
||||||
get_affiliations/3, search_affiliation/4]).
|
get_affiliations/3, search_affiliation/4]).
|
||||||
|
|
||||||
|
@ -145,6 +150,39 @@ get_affiliations(_ServerHost, _Room, _Host) ->
|
||||||
search_affiliation(_ServerHost, _Room, _Host, _Affiliation) ->
|
search_affiliation(_ServerHost, _Room, _Host, _Affiliation) ->
|
||||||
{error, not_implemented}.
|
{error, not_implemented}.
|
||||||
|
|
||||||
|
register_online_room(_, _, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
unregister_online_room(_, _, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
find_online_room(_, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
count_online_rooms(_) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
get_online_rooms(_, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
handle_event(_) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
rsm_supported() ->
|
||||||
|
false.
|
||||||
|
|
||||||
|
register_online_user(_, _, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
unregister_online_user(_, _, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
count_online_rooms_by_user(_, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
|
get_online_rooms_by_user(_, _) ->
|
||||||
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
export(_Server) ->
|
export(_Server) ->
|
||||||
[{muc_room,
|
[{muc_room,
|
||||||
fun(Host, #muc_room{name_host = {Name, RoomHost}, opts = Opts}) ->
|
fun(Host, #muc_room{name_host = {Name, RoomHost}, opts = Opts}) ->
|
||||||
|
|
|
@ -148,8 +148,6 @@ init([Host, Opts]) ->
|
||||||
ejabberd_hooks:add(c2s_self_presence, Host, ?MODULE, c2s_self_presence, 50),
|
ejabberd_hooks:add(c2s_self_presence, Host, ?MODULE, c2s_self_presence, 50),
|
||||||
ejabberd_hooks:add(remove_user, Host,
|
ejabberd_hooks:add(remove_user, Host,
|
||||||
?MODULE, remove_user, 50),
|
?MODULE, remove_user, 50),
|
||||||
ejabberd_hooks:add(anonymous_purge_hook, Host,
|
|
||||||
?MODULE, remove_user, 50),
|
|
||||||
ejabberd_hooks:add(disco_sm_features, Host,
|
ejabberd_hooks:add(disco_sm_features, Host,
|
||||||
?MODULE, get_sm_features, 50),
|
?MODULE, get_sm_features, 50),
|
||||||
ejabberd_hooks:add(disco_local_features, Host,
|
ejabberd_hooks:add(disco_local_features, Host,
|
||||||
|
@ -208,8 +206,6 @@ terminate(_Reason, State) ->
|
||||||
ejabberd_hooks:delete(c2s_self_presence, Host, ?MODULE, c2s_self_presence, 50),
|
ejabberd_hooks:delete(c2s_self_presence, Host, ?MODULE, c2s_self_presence, 50),
|
||||||
ejabberd_hooks:delete(remove_user, Host, ?MODULE,
|
ejabberd_hooks:delete(remove_user, Host, ?MODULE,
|
||||||
remove_user, 50),
|
remove_user, 50),
|
||||||
ejabberd_hooks:delete(anonymous_purge_hook, Host,
|
|
||||||
?MODULE, remove_user, 50),
|
|
||||||
ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
|
ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
|
||||||
ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_sm_features, 50),
|
ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_sm_features, 50),
|
||||||
ejabberd_hooks:delete(disco_sm_identity, Host, ?MODULE, get_sm_identity, 50),
|
ejabberd_hooks:delete(disco_sm_identity, Host, ?MODULE, get_sm_identity, 50),
|
||||||
|
|
|
@ -303,8 +303,6 @@ init([ServerHost, Opts]) ->
|
||||||
?MODULE, out_subscription, 50),
|
?MODULE, out_subscription, 50),
|
||||||
ejabberd_hooks:add(remove_user, ServerHost,
|
ejabberd_hooks:add(remove_user, ServerHost,
|
||||||
?MODULE, remove_user, 50),
|
?MODULE, remove_user, 50),
|
||||||
ejabberd_hooks:add(anonymous_purge_hook, ServerHost,
|
|
||||||
?MODULE, remove_user, 50),
|
|
||||||
ejabberd_hooks:add(c2s_handle_info, ServerHost,
|
ejabberd_hooks:add(c2s_handle_info, ServerHost,
|
||||||
?MODULE, c2s_handle_info, 50),
|
?MODULE, c2s_handle_info, 50),
|
||||||
gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO,
|
gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO,
|
||||||
|
@ -912,8 +910,6 @@ terminate(_Reason,
|
||||||
?MODULE, out_subscription, 50),
|
?MODULE, out_subscription, 50),
|
||||||
ejabberd_hooks:delete(remove_user, ServerHost,
|
ejabberd_hooks:delete(remove_user, ServerHost,
|
||||||
?MODULE, remove_user, 50),
|
?MODULE, remove_user, 50),
|
||||||
ejabberd_hooks:delete(anonymous_purge_hook, ServerHost,
|
|
||||||
?MODULE, remove_user, 50),
|
|
||||||
ejabberd_hooks:delete(c2s_handle_info, ServerHost,
|
ejabberd_hooks:delete(c2s_handle_info, ServerHost,
|
||||||
?MODULE, c2s_handle_info, 50),
|
?MODULE, c2s_handle_info, 50),
|
||||||
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO),
|
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO),
|
||||||
|
|
|
@ -100,8 +100,6 @@ start(Host, Opts) ->
|
||||||
get_jid_info, 50),
|
get_jid_info, 50),
|
||||||
ejabberd_hooks:add(remove_user, Host, ?MODULE,
|
ejabberd_hooks:add(remove_user, Host, ?MODULE,
|
||||||
remove_user, 50),
|
remove_user, 50),
|
||||||
ejabberd_hooks:add(anonymous_purge_hook, Host, ?MODULE,
|
|
||||||
remove_user, 50),
|
|
||||||
ejabberd_hooks:add(c2s_self_presence, Host, ?MODULE,
|
ejabberd_hooks:add(c2s_self_presence, Host, ?MODULE,
|
||||||
c2s_self_presence, 50),
|
c2s_self_presence, 50),
|
||||||
ejabberd_hooks:add(c2s_post_auth_features, Host,
|
ejabberd_hooks:add(c2s_post_auth_features, Host,
|
||||||
|
@ -128,8 +126,6 @@ stop(Host) ->
|
||||||
?MODULE, get_jid_info, 50),
|
?MODULE, get_jid_info, 50),
|
||||||
ejabberd_hooks:delete(remove_user, Host, ?MODULE,
|
ejabberd_hooks:delete(remove_user, Host, ?MODULE,
|
||||||
remove_user, 50),
|
remove_user, 50),
|
||||||
ejabberd_hooks:delete(anonymous_purge_hook, Host,
|
|
||||||
?MODULE, remove_user, 50),
|
|
||||||
ejabberd_hooks:delete(c2s_self_presence, Host, ?MODULE,
|
ejabberd_hooks:delete(c2s_self_presence, Host, ?MODULE,
|
||||||
c2s_self_presence, 50),
|
c2s_self_presence, 50),
|
||||||
ejabberd_hooks:delete(c2s_post_auth_features,
|
ejabberd_hooks:delete(c2s_post_auth_features,
|
||||||
|
|
|
@ -98,8 +98,6 @@ start(Host, Opts) ->
|
||||||
unset_presence, 50),
|
unset_presence, 50),
|
||||||
ejabberd_hooks:add(register_user, Host, ?MODULE,
|
ejabberd_hooks:add(register_user, Host, ?MODULE,
|
||||||
register_user, 50),
|
register_user, 50),
|
||||||
ejabberd_hooks:add(anonymous_purge_hook, Host, ?MODULE,
|
|
||||||
remove_user, 50),
|
|
||||||
ejabberd_hooks:add(remove_user, Host, ?MODULE,
|
ejabberd_hooks:add(remove_user, Host, ?MODULE,
|
||||||
remove_user, 50).
|
remove_user, 50).
|
||||||
|
|
||||||
|
@ -126,8 +124,6 @@ stop(Host) ->
|
||||||
?MODULE, unset_presence, 50),
|
?MODULE, unset_presence, 50),
|
||||||
ejabberd_hooks:delete(register_user, Host, ?MODULE,
|
ejabberd_hooks:delete(register_user, Host, ?MODULE,
|
||||||
register_user, 50),
|
register_user, 50),
|
||||||
ejabberd_hooks:delete(anonymous_purge_hook, Host,
|
|
||||||
?MODULE, remove_user, 50),
|
|
||||||
ejabberd_hooks:delete(remove_user, Host, ?MODULE,
|
ejabberd_hooks:delete(remove_user, Host, ?MODULE,
|
||||||
remove_user,
|
remove_user,
|
||||||
50).
|
50).
|
||||||
|
|
Loading…
Reference in New Issue