mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-28 16:34:13 +01:00
Add SQL as mod_muc RAM backend
This commit is contained in:
parent
ba6c88cb90
commit
12e01a5119
21
sql/lite.sql
21
sql/lite.sql
@ -275,6 +275,27 @@ CREATE TABLE muc_registered (
|
|||||||
CREATE INDEX i_muc_registered_nick ON muc_registered (nick);
|
CREATE INDEX i_muc_registered_nick ON muc_registered (nick);
|
||||||
CREATE UNIQUE INDEX i_muc_registered_jid_host ON muc_registered (jid, host);
|
CREATE UNIQUE INDEX i_muc_registered_jid_host ON muc_registered (jid, host);
|
||||||
|
|
||||||
|
CREATE TABLE muc_online_room (
|
||||||
|
name text NOT NULL,
|
||||||
|
host text NOT NULL,
|
||||||
|
node text NOT NULL,
|
||||||
|
pid text NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX i_muc_online_room_name_host ON muc_online_room (name, host);
|
||||||
|
|
||||||
|
CREATE TABLE muc_online_users (
|
||||||
|
username text NOT NULL,
|
||||||
|
server text NOT NULL,
|
||||||
|
resource text NOT NULL,
|
||||||
|
name text NOT NULL,
|
||||||
|
host text NOT NULL,
|
||||||
|
node text NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX i_muc_online_users ON muc_online_users (username, server, resource, name, host);
|
||||||
|
CREATE INDEX i_muc_online_users_us ON muc_online_users (username, server);
|
||||||
|
|
||||||
CREATE TABLE irc_custom (
|
CREATE TABLE irc_custom (
|
||||||
jid text NOT NULL,
|
jid text NOT NULL,
|
||||||
host text NOT NULL,
|
host text NOT NULL,
|
||||||
|
@ -125,6 +125,30 @@ CREATE TABLE [dbo].[muc_room] (
|
|||||||
CREATE UNIQUE CLUSTERED INDEX [muc_room_name_host] ON [muc_room] (name, host)
|
CREATE UNIQUE CLUSTERED INDEX [muc_room_name_host] ON [muc_room] (name, host)
|
||||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
|
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[muc_online_room] (
|
||||||
|
[name] [varchar] (250) NOT NULL,
|
||||||
|
[host] [varchar] (250) NOT NULL,
|
||||||
|
[node] [text] NOT NULL,
|
||||||
|
[pid] [text] NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE CLUSTERED INDEX [muc_online_room_name_host] ON [muc_online_room] (name, host)
|
||||||
|
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[muc_online_users] (
|
||||||
|
[username] [varchar] (250) NOT NULL,
|
||||||
|
[server] [varchar] (250) NOT NULL,
|
||||||
|
[resource] [varchar] (250) NOT NULL,
|
||||||
|
[name] [varchar] (250) NOT NULL,
|
||||||
|
[host] [varchar] (250) NOT NULL,
|
||||||
|
node text NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE CLUSTERED INDEX [muc_online_users_i] ON [muc_online_users] (username, server, resource, name, host)
|
||||||
|
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
|
||||||
|
CREATE UNIQUE CLUSTERED INDEX [muc_online_users_us] ON [muc_online_users] (username, server);
|
||||||
|
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
|
||||||
|
|
||||||
CREATE TABLE [dbo].[privacy_default_list] (
|
CREATE TABLE [dbo].[privacy_default_list] (
|
||||||
[username] [varchar] (250) NOT NULL,
|
[username] [varchar] (250) NOT NULL,
|
||||||
[name] [varchar] (250) NOT NULL,
|
[name] [varchar] (250) NOT NULL,
|
||||||
|
@ -291,6 +291,27 @@ CREATE TABLE muc_registered (
|
|||||||
CREATE INDEX i_muc_registered_nick USING BTREE ON muc_registered(nick(75));
|
CREATE INDEX i_muc_registered_nick USING BTREE ON muc_registered(nick(75));
|
||||||
CREATE UNIQUE INDEX i_muc_registered_jid_host USING BTREE ON muc_registered(jid(75), host(75));
|
CREATE UNIQUE INDEX i_muc_registered_jid_host USING BTREE ON muc_registered(jid(75), host(75));
|
||||||
|
|
||||||
|
CREATE TABLE muc_online_room (
|
||||||
|
name text NOT NULL,
|
||||||
|
host text NOT NULL,
|
||||||
|
node text NOT NULL,
|
||||||
|
pid text NOT NULL
|
||||||
|
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX i_muc_online_room_name_host USING BTREE ON muc_online_room(name(75), host(75));
|
||||||
|
|
||||||
|
CREATE TABLE muc_online_users (
|
||||||
|
username text NOT NULL,
|
||||||
|
server text NOT NULL,
|
||||||
|
resource text NOT NULL,
|
||||||
|
name text NOT NULL,
|
||||||
|
host text NOT NULL,
|
||||||
|
node text NOT NULL
|
||||||
|
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX i_muc_online_users USING BTREE ON muc_online_users(username(75), server(75), resource(75), name(75), host(75));
|
||||||
|
CREATE INDEX i_muc_online_users_us USING BTREE ON muc_online_users(username(75), server(75));
|
||||||
|
|
||||||
CREATE TABLE irc_custom (
|
CREATE TABLE irc_custom (
|
||||||
jid text NOT NULL,
|
jid text NOT NULL,
|
||||||
host text NOT NULL,
|
host text NOT NULL,
|
||||||
|
21
sql/pg.sql
21
sql/pg.sql
@ -293,6 +293,27 @@ CREATE TABLE muc_registered (
|
|||||||
CREATE INDEX i_muc_registered_nick ON muc_registered USING btree (nick);
|
CREATE INDEX i_muc_registered_nick ON muc_registered USING btree (nick);
|
||||||
CREATE UNIQUE INDEX i_muc_registered_jid_host ON muc_registered USING btree (jid, host);
|
CREATE UNIQUE INDEX i_muc_registered_jid_host ON muc_registered USING btree (jid, host);
|
||||||
|
|
||||||
|
CREATE TABLE muc_online_room (
|
||||||
|
name text NOT NULL,
|
||||||
|
host text NOT NULL,
|
||||||
|
node text NOT NULL,
|
||||||
|
pid text NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX i_muc_online_room_name_host ON muc_online_room USING btree (name, host);
|
||||||
|
|
||||||
|
CREATE TABLE muc_online_users (
|
||||||
|
username text NOT NULL,
|
||||||
|
server text NOT NULL,
|
||||||
|
resource text NOT NULL,
|
||||||
|
name text NOT NULL,
|
||||||
|
host text NOT NULL,
|
||||||
|
node text NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX i_muc_online_users ON muc_online_users USING btree (username, server, resource, name, host);
|
||||||
|
CREATE INDEX i_muc_online_users_us ON muc_online_users USING btree (username, server);
|
||||||
|
|
||||||
CREATE TABLE irc_custom (
|
CREATE TABLE irc_custom (
|
||||||
jid text NOT NULL,
|
jid text NOT NULL,
|
||||||
host text NOT NULL,
|
host text NOT NULL,
|
||||||
|
@ -94,16 +94,16 @@
|
|||||||
-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 register_online_room(binary(), binary(), binary(), pid()) -> any().
|
||||||
-callback unregister_online_room(binary(), binary(), pid()) -> any().
|
-callback unregister_online_room(binary(), binary(), binary(), pid()) -> any().
|
||||||
-callback find_online_room(binary(), binary()) -> {ok, pid()} | error.
|
-callback find_online_room(binary(), binary(), binary()) -> {ok, pid()} | error.
|
||||||
-callback get_online_rooms(binary(), undefined | rsm_set()) -> [{binary(), binary(), pid()}].
|
-callback get_online_rooms(binary(), binary(), undefined | rsm_set()) -> [{binary(), binary(), pid()}].
|
||||||
-callback count_online_rooms(binary()) -> non_neg_integer().
|
-callback count_online_rooms(binary(), binary()) -> non_neg_integer().
|
||||||
-callback rsm_supported() -> boolean().
|
-callback rsm_supported() -> boolean().
|
||||||
-callback register_online_user(ljid(), binary(), binary()) -> any().
|
-callback register_online_user(binary(), ljid(), binary(), binary()) -> any().
|
||||||
-callback unregister_online_user(ljid(), binary(), binary()) -> any().
|
-callback unregister_online_user(binary(), ljid(), binary(), binary()) -> any().
|
||||||
-callback count_online_rooms_by_user(binary(), binary()) -> non_neg_integer().
|
-callback count_online_rooms_by_user(binary(), binary(), binary()) -> non_neg_integer().
|
||||||
-callback get_online_rooms_by_user(binary(), binary()) -> [{binary(), binary()}].
|
-callback get_online_rooms_by_user(binary(), binary(), binary()) -> [{binary(), binary()}].
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% API
|
%% API
|
||||||
@ -127,7 +127,7 @@ shutdown_rooms(Host) ->
|
|||||||
RMod = gen_mod:ram_db_mod(Host, ?MODULE),
|
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 = RMod:get_online_rooms(MyHost, undefined),
|
Rooms = RMod:get_online_rooms(Host, MyHost, undefined),
|
||||||
lists:flatmap(
|
lists:flatmap(
|
||||||
fun({_, _, Pid}) when node(Pid) == node() ->
|
fun({_, _, Pid}) when node(Pid) == node() ->
|
||||||
Pid ! shutdown,
|
Pid ! shutdown,
|
||||||
@ -180,13 +180,13 @@ can_use_nick(ServerHost, Host, JID, Nick) ->
|
|||||||
find_online_room(Room, Host) ->
|
find_online_room(Room, Host) ->
|
||||||
ServerHost = ejabberd_router:host_of_route(Host),
|
ServerHost = ejabberd_router:host_of_route(Host),
|
||||||
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
RMod:find_online_room(Room, Host).
|
RMod:find_online_room(ServerHost, Room, Host).
|
||||||
|
|
||||||
-spec register_online_room(binary(), binary(), pid()) -> any().
|
-spec register_online_room(binary(), binary(), pid()) -> any().
|
||||||
register_online_room(Room, Host, Pid) ->
|
register_online_room(Room, Host, Pid) ->
|
||||||
ServerHost = ejabberd_router:host_of_route(Host),
|
ServerHost = ejabberd_router:host_of_route(Host),
|
||||||
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
RMod:register_online_room(Room, Host, Pid).
|
RMod:register_online_room(ServerHost, Room, Host, Pid).
|
||||||
|
|
||||||
-spec get_online_rooms(binary()) -> [{binary(), binary(), pid()}].
|
-spec get_online_rooms(binary()) -> [{binary(), binary(), pid()}].
|
||||||
get_online_rooms(Host) ->
|
get_online_rooms(Host) ->
|
||||||
@ -201,22 +201,22 @@ count_online_rooms(Host) ->
|
|||||||
-spec register_online_user(binary(), ljid(), binary(), binary()) -> any().
|
-spec register_online_user(binary(), ljid(), binary(), binary()) -> any().
|
||||||
register_online_user(ServerHost, LJID, Name, Host) ->
|
register_online_user(ServerHost, LJID, Name, Host) ->
|
||||||
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
RMod:register_online_user(LJID, Name, Host).
|
RMod:register_online_user(ServerHost, LJID, Name, Host).
|
||||||
|
|
||||||
-spec unregister_online_user(binary(), ljid(), binary(), binary()) -> any().
|
-spec unregister_online_user(binary(), ljid(), binary(), binary()) -> any().
|
||||||
unregister_online_user(ServerHost, LJID, Name, Host) ->
|
unregister_online_user(ServerHost, LJID, Name, Host) ->
|
||||||
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
RMod:unregister_online_user(LJID, Name, Host).
|
RMod:unregister_online_user(ServerHost, LJID, Name, Host).
|
||||||
|
|
||||||
-spec count_online_rooms_by_user(binary(), binary(), binary()) -> non_neg_integer().
|
-spec count_online_rooms_by_user(binary(), binary(), binary()) -> non_neg_integer().
|
||||||
count_online_rooms_by_user(ServerHost, LUser, LServer) ->
|
count_online_rooms_by_user(ServerHost, LUser, LServer) ->
|
||||||
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
RMod:count_online_rooms_by_user(LUser, LServer).
|
RMod:count_online_rooms_by_user(ServerHost, LUser, LServer).
|
||||||
|
|
||||||
-spec get_online_rooms_by_user(binary(), binary(), binary()) -> [{binary(), binary()}].
|
-spec get_online_rooms_by_user(binary(), binary(), binary()) -> [{binary(), binary()}].
|
||||||
get_online_rooms_by_user(ServerHost, LUser, LServer) ->
|
get_online_rooms_by_user(ServerHost, LUser, LServer) ->
|
||||||
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
RMod:get_online_rooms_by_user(LUser, LServer).
|
RMod:get_online_rooms_by_user(ServerHost, LUser, LServer).
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
@ -256,7 +256,7 @@ handle_call({create, Room, From, Nick, Opts}, _From,
|
|||||||
RoomShaper, From,
|
RoomShaper, From,
|
||||||
Nick, NewOpts, QueueType),
|
Nick, NewOpts, QueueType),
|
||||||
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
RMod:register_online_room(Room, Host, Pid),
|
RMod:register_online_room(ServerHost, Room, Host, Pid),
|
||||||
{reply, ok, State}.
|
{reply, ok, State}.
|
||||||
|
|
||||||
handle_cast({reload, ServerHost, NewOpts, OldOpts}, #state{host = OldHost}) ->
|
handle_cast({reload, ServerHost, NewOpts, OldOpts}, #state{host = OldHost}) ->
|
||||||
@ -318,7 +318,7 @@ handle_info({route, Packet},
|
|||||||
handle_info({room_destroyed, {Room, Host}, Pid}, State) ->
|
handle_info({room_destroyed, {Room, Host}, Pid}, State) ->
|
||||||
ServerHost = State#state.server_host,
|
ServerHost = State#state.server_host,
|
||||||
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
RMod:unregister_online_room(Room, Host, Pid),
|
RMod:unregister_online_room(ServerHost, Room, Host, Pid),
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_info(Info, State) ->
|
handle_info(Info, State) ->
|
||||||
?ERROR_MSG("unexpected info: ~p", [Info]),
|
?ERROR_MSG("unexpected info: ~p", [Info]),
|
||||||
@ -491,7 +491,7 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper,
|
|||||||
{_AccessRoute, AccessCreate, _AccessAdmin, _AccessPersistent} = Access,
|
{_AccessRoute, AccessCreate, _AccessAdmin, _AccessPersistent} = Access,
|
||||||
{Room, _, Nick} = jid:tolower(To),
|
{Room, _, Nick} = jid:tolower(To),
|
||||||
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
case RMod:find_online_room(Room, Host) of
|
case RMod:find_online_room(ServerHost, Room, Host) of
|
||||||
error ->
|
error ->
|
||||||
case is_create_request(Packet) of
|
case is_create_request(Packet) of
|
||||||
true ->
|
true ->
|
||||||
@ -504,7 +504,7 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper,
|
|||||||
Room, HistorySize,
|
Room, HistorySize,
|
||||||
RoomShaper, From, Nick, DefRoomOpts,
|
RoomShaper, From, Nick, DefRoomOpts,
|
||||||
QueueType),
|
QueueType),
|
||||||
RMod:register_online_room(Room, Host, Pid),
|
RMod:register_online_room(ServerHost, Room, Host, Pid),
|
||||||
mod_muc_room:route(Pid, Packet),
|
mod_muc_room:route(Pid, Packet),
|
||||||
ok;
|
ok;
|
||||||
false ->
|
false ->
|
||||||
@ -675,13 +675,13 @@ load_permanent_rooms(Host, ServerHost, Access,
|
|||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun(R) ->
|
fun(R) ->
|
||||||
{Room, Host} = R#muc_room.name_host,
|
{Room, Host} = R#muc_room.name_host,
|
||||||
case RMod:find_online_room(Room, Host) of
|
case RMod:find_online_room(ServerHost, Room, Host) of
|
||||||
error ->
|
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, QueueType),
|
R#muc_room.opts, QueueType),
|
||||||
RMod:register_online_room(Room, Host, Pid);
|
RMod:register_online_room(ServerHost, Room, Host, Pid);
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
ok
|
ok
|
||||||
end
|
end
|
||||||
@ -856,12 +856,12 @@ get_online_rooms(ServerHost, Host) ->
|
|||||||
[{binary(), binary(), pid()}].
|
[{binary(), binary(), pid()}].
|
||||||
get_online_rooms(ServerHost, Host, RSM) ->
|
get_online_rooms(ServerHost, Host, RSM) ->
|
||||||
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
RMod:get_online_rooms(Host, RSM).
|
RMod:get_online_rooms(ServerHost, Host, RSM).
|
||||||
|
|
||||||
-spec count_online_rooms(binary(), binary()) -> non_neg_integer().
|
-spec count_online_rooms(binary(), binary()) -> non_neg_integer().
|
||||||
count_online_rooms(ServerHost, Host) ->
|
count_online_rooms(ServerHost, Host) ->
|
||||||
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
|
||||||
RMod:count_online_rooms(Host).
|
RMod:count_online_rooms(ServerHost, Host).
|
||||||
|
|
||||||
opts_to_binary(Opts) ->
|
opts_to_binary(Opts) ->
|
||||||
lists:map(
|
lists:map(
|
||||||
|
@ -30,10 +30,10 @@
|
|||||||
%% 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,
|
-export([register_online_room/4, unregister_online_room/4, find_online_room/3,
|
||||||
get_online_rooms/2, count_online_rooms/1, rsm_supported/0,
|
get_online_rooms/3, count_online_rooms/2, rsm_supported/0,
|
||||||
register_online_user/3, unregister_online_user/3,
|
register_online_user/4, unregister_online_user/4,
|
||||||
count_online_rooms_by_user/2, get_online_rooms_by_user/2]).
|
count_online_rooms_by_user/3, get_online_rooms_by_user/3]).
|
||||||
-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]).
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
@ -157,27 +157,30 @@ 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) ->
|
register_online_room(_ServerHost, Room, Host, Pid) ->
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
mnesia:write(
|
mnesia:write(
|
||||||
#muc_online_room{name_host = {Room, Host}, pid = Pid})
|
#muc_online_room{name_host = {Room, Host}, pid = Pid})
|
||||||
end,
|
end,
|
||||||
mnesia:transaction(F).
|
mnesia:transaction(F).
|
||||||
|
|
||||||
unregister_online_room(Room, Host, Pid) ->
|
unregister_online_room(_ServerHost, Room, Host, Pid) ->
|
||||||
F = fun () ->
|
F = fun () ->
|
||||||
mnesia:delete_object(
|
mnesia:delete_object(
|
||||||
#muc_online_room{name_host = {Room, Host}, pid = Pid})
|
#muc_online_room{name_host = {Room, Host}, pid = Pid})
|
||||||
end,
|
end,
|
||||||
mnesia:transaction(F).
|
mnesia:transaction(F).
|
||||||
|
|
||||||
|
find_online_room(_ServerHost, Room, Host) ->
|
||||||
|
find_online_room(Room, Host).
|
||||||
|
|
||||||
find_online_room(Room, Host) ->
|
find_online_room(Room, Host) ->
|
||||||
case mnesia:dirty_read(muc_online_room, {Room, Host}) of
|
case mnesia:dirty_read(muc_online_room, {Room, Host}) of
|
||||||
[] -> error;
|
[] -> error;
|
||||||
[#muc_online_room{pid = Pid}] -> {ok, Pid}
|
[#muc_online_room{pid = Pid}] -> {ok, Pid}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
count_online_rooms(Host) ->
|
count_online_rooms(_ServerHost, Host) ->
|
||||||
ets:select_count(
|
ets:select_count(
|
||||||
muc_online_room,
|
muc_online_room,
|
||||||
ets:fun2ms(
|
ets:fun2ms(
|
||||||
@ -185,20 +188,20 @@ count_online_rooms(Host) ->
|
|||||||
H == Host
|
H == Host
|
||||||
end)).
|
end)).
|
||||||
|
|
||||||
get_online_rooms(Host,
|
get_online_rooms(_ServerHost, Host,
|
||||||
#rsm_set{max = Max, 'after' = After, before = undefined})
|
#rsm_set{max = Max, 'after' = After, before = undefined})
|
||||||
when is_binary(After), After /= <<"">> ->
|
when is_binary(After), After /= <<"">> ->
|
||||||
lists:reverse(get_online_rooms(next, {After, Host}, Host, 0, Max, []));
|
lists:reverse(get_online_rooms(next, {After, Host}, Host, 0, Max, []));
|
||||||
get_online_rooms(Host,
|
get_online_rooms(_ServerHost, Host,
|
||||||
#rsm_set{max = Max, 'after' = undefined, before = Before})
|
#rsm_set{max = Max, 'after' = undefined, before = Before})
|
||||||
when is_binary(Before), Before /= <<"">> ->
|
when is_binary(Before), Before /= <<"">> ->
|
||||||
get_online_rooms(prev, {Before, Host}, Host, 0, Max, []);
|
get_online_rooms(prev, {Before, Host}, Host, 0, Max, []);
|
||||||
get_online_rooms(Host,
|
get_online_rooms(_ServerHost, Host,
|
||||||
#rsm_set{max = Max, 'after' = undefined, before = <<"">>}) ->
|
#rsm_set{max = Max, 'after' = undefined, before = <<"">>}) ->
|
||||||
get_online_rooms(last, {<<"">>, Host}, Host, 0, Max, []);
|
get_online_rooms(last, {<<"">>, Host}, Host, 0, Max, []);
|
||||||
get_online_rooms(Host, #rsm_set{max = Max}) ->
|
get_online_rooms(_ServerHost, Host, #rsm_set{max = Max}) ->
|
||||||
lists:reverse(get_online_rooms(first, {<<"">>, Host}, Host, 0, Max, []));
|
lists:reverse(get_online_rooms(first, {<<"">>, Host}, Host, 0, Max, []));
|
||||||
get_online_rooms(Host, undefined) ->
|
get_online_rooms(_ServerHost, Host, undefined) ->
|
||||||
mnesia:dirty_select(
|
mnesia:dirty_select(
|
||||||
muc_online_room,
|
muc_online_room,
|
||||||
ets:fun2ms(
|
ets:fun2ms(
|
||||||
@ -248,17 +251,17 @@ get_online_rooms(Action, Key, Host, Count, Max, Items) ->
|
|||||||
rsm_supported() ->
|
rsm_supported() ->
|
||||||
true.
|
true.
|
||||||
|
|
||||||
register_online_user({U, S, R}, Room, Host) ->
|
register_online_user(_ServerHost, {U, S, R}, Room, Host) ->
|
||||||
ets:insert(muc_online_users,
|
ets:insert(muc_online_users,
|
||||||
#muc_online_users{us = {U, S}, resource = R,
|
#muc_online_users{us = {U, S}, resource = R,
|
||||||
room = Room, host = Host}).
|
room = Room, host = Host}).
|
||||||
|
|
||||||
unregister_online_user({U, S, R}, Room, Host) ->
|
unregister_online_user(_ServerHost, {U, S, R}, Room, Host) ->
|
||||||
ets:delete_object(muc_online_users,
|
ets:delete_object(muc_online_users,
|
||||||
#muc_online_users{us = {U, S}, resource = R,
|
#muc_online_users{us = {U, S}, resource = R,
|
||||||
room = Room, host = Host}).
|
room = Room, host = Host}).
|
||||||
|
|
||||||
count_online_rooms_by_user(U, S) ->
|
count_online_rooms_by_user(_ServerHost, U, S) ->
|
||||||
ets:select_count(
|
ets:select_count(
|
||||||
muc_online_users,
|
muc_online_users,
|
||||||
ets:fun2ms(
|
ets:fun2ms(
|
||||||
@ -266,7 +269,7 @@ count_online_rooms_by_user(U, S) ->
|
|||||||
U == U1 andalso S == S1
|
U == U1 andalso S == S1
|
||||||
end)).
|
end)).
|
||||||
|
|
||||||
get_online_rooms_by_user(U, S) ->
|
get_online_rooms_by_user(_ServerHost, U, S) ->
|
||||||
ets:select(
|
ets:select(
|
||||||
muc_online_users,
|
muc_online_users,
|
||||||
ets:fun2ms(
|
ets:fun2ms(
|
||||||
|
@ -30,10 +30,10 @@
|
|||||||
%% 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,
|
-export([register_online_room/4, unregister_online_room/4, find_online_room/3,
|
||||||
get_online_rooms/2, count_online_rooms/1, rsm_supported/0,
|
get_online_rooms/3, count_online_rooms/2, rsm_supported/0,
|
||||||
register_online_user/3, unregister_online_user/3,
|
register_online_user/4, unregister_online_user/4,
|
||||||
count_online_rooms_by_user/2, get_online_rooms_by_user/2]).
|
count_online_rooms_by_user/3, get_online_rooms_by_user/3]).
|
||||||
-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]).
|
||||||
|
|
||||||
@ -140,34 +140,34 @@ 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(_, _, _) ->
|
register_online_room(_, _, _, _) ->
|
||||||
erlang:error(not_implemented).
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
unregister_online_room(_, _, _) ->
|
unregister_online_room(_, _, _, _) ->
|
||||||
erlang:error(not_implemented).
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
find_online_room(_, _) ->
|
find_online_room(_, _, _) ->
|
||||||
erlang:error(not_implemented).
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
count_online_rooms(_) ->
|
count_online_rooms(_, _) ->
|
||||||
erlang:error(not_implemented).
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
get_online_rooms(_, _) ->
|
get_online_rooms(_, _, _) ->
|
||||||
erlang:error(not_implemented).
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
rsm_supported() ->
|
rsm_supported() ->
|
||||||
false.
|
false.
|
||||||
|
|
||||||
register_online_user(_, _, _) ->
|
register_online_user(_, _, _, _) ->
|
||||||
erlang:error(not_implemented).
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
unregister_online_user(_, _, _) ->
|
unregister_online_user(_, _, _, _) ->
|
||||||
erlang:error(not_implemented).
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
count_online_rooms_by_user(_, _) ->
|
count_online_rooms_by_user(_, _, _) ->
|
||||||
erlang:error(not_implemented).
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
get_online_rooms_by_user(_, _) ->
|
get_online_rooms_by_user(_, _, _) ->
|
||||||
erlang:error(not_implemented).
|
erlang:error(not_implemented).
|
||||||
|
|
||||||
import(_LServer, <<"muc_room">>,
|
import(_LServer, <<"muc_room">>,
|
||||||
|
@ -33,10 +33,10 @@
|
|||||||
-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,
|
-export([register_online_room/4, unregister_online_room/4, find_online_room/3,
|
||||||
get_online_rooms/2, count_online_rooms/1, rsm_supported/0,
|
get_online_rooms/3, count_online_rooms/2, rsm_supported/0,
|
||||||
register_online_user/3, unregister_online_user/3,
|
register_online_user/4, unregister_online_user/4,
|
||||||
count_online_rooms_by_user/2, get_online_rooms_by_user/2]).
|
count_online_rooms_by_user/3, get_online_rooms_by_user/3]).
|
||||||
-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]).
|
||||||
|
|
||||||
@ -48,8 +48,13 @@
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _Opts) ->
|
init(Host, Opts) ->
|
||||||
ok.
|
case gen_mod:ram_db_mod(Host, Opts, mod_muc) of
|
||||||
|
?MODULE ->
|
||||||
|
clean_tables(Host);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
store_room(LServer, Host, Name, Opts) ->
|
store_room(LServer, Host, Name, Opts) ->
|
||||||
SOpts = jlib:term_to_expr(Opts),
|
SOpts = jlib:term_to_expr(Opts),
|
||||||
@ -165,35 +170,126 @@ 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(_, _, _) ->
|
register_online_room(ServerHost, Room, Host, Pid) ->
|
||||||
erlang:error(not_implemented).
|
PidS = enc_pid(Pid),
|
||||||
|
NodeS = erlang:atom_to_binary(node(Pid), latin1),
|
||||||
|
case ?SQL_UPSERT(ServerHost,
|
||||||
|
"muc_online_room",
|
||||||
|
["!name=%(Room)s",
|
||||||
|
"!host=%(Host)s",
|
||||||
|
"node=%(NodeS)s",
|
||||||
|
"pid=%(PidS)s"]) of
|
||||||
|
ok ->
|
||||||
|
ok;
|
||||||
|
Err ->
|
||||||
|
?ERROR_MSG("failed to update 'muc_online_room': ~p", [Err]),
|
||||||
|
Err
|
||||||
|
end.
|
||||||
|
|
||||||
unregister_online_room(_, _, _) ->
|
unregister_online_room(ServerHost, Room, Host, Pid) ->
|
||||||
erlang:error(not_implemented).
|
%% TODO: report errors
|
||||||
|
PidS = enc_pid(Pid),
|
||||||
|
NodeS = erlang:atom_to_binary(node(Pid), latin1),
|
||||||
|
ejabberd_sql:sql_query(
|
||||||
|
ServerHost,
|
||||||
|
?SQL("delete from muc_online_room where name=%(Room)s and "
|
||||||
|
"host=%(Host)s and node=%(NodeS)s and pid=%(PidS)s")).
|
||||||
|
|
||||||
find_online_room(_, _) ->
|
find_online_room(ServerHost, Room, Host) ->
|
||||||
erlang:error(not_implemented).
|
case ejabberd_sql:sql_query(
|
||||||
|
ServerHost,
|
||||||
|
?SQL("select @(pid)s, @(node)s from muc_online_room where "
|
||||||
|
"name=%(Room)s and host=%(Host)s")) of
|
||||||
|
{selected, [{PidS, NodeS}]} ->
|
||||||
|
try {ok, dec_pid(PidS, NodeS)}
|
||||||
|
catch _:{node_down, _} -> error
|
||||||
|
end;
|
||||||
|
{selected, []} ->
|
||||||
|
error;
|
||||||
|
Err ->
|
||||||
|
?ERROR_MSG("failed to select 'muc_online_room': ~p", [Err]),
|
||||||
|
error
|
||||||
|
end.
|
||||||
|
|
||||||
count_online_rooms(_) ->
|
count_online_rooms(ServerHost, Host) ->
|
||||||
erlang:error(not_implemented).
|
case ejabberd_sql:sql_query(
|
||||||
|
ServerHost,
|
||||||
|
?SQL("select @(count(*))d from muc_online_room "
|
||||||
|
"where host=%(Host)s")) of
|
||||||
|
{selected, [{Num}]} ->
|
||||||
|
Num;
|
||||||
|
Err ->
|
||||||
|
?ERROR_MSG("failed to select 'muc_online_room': ~p", [Err]),
|
||||||
|
0
|
||||||
|
end.
|
||||||
|
|
||||||
get_online_rooms(_, _) ->
|
get_online_rooms(ServerHost, Host, _RSM) ->
|
||||||
erlang:error(not_implemented).
|
case ejabberd_sql:sql_query(
|
||||||
|
ServerHost,
|
||||||
|
?SQL("select @(name)s, @(pid)s, @(node)s from muc_online_room "
|
||||||
|
"where host=%(Host)s")) of
|
||||||
|
{selected, Rows} ->
|
||||||
|
lists:flatmap(
|
||||||
|
fun({Room, PidS, NodeS}) ->
|
||||||
|
try [{Room, Host, dec_pid(PidS, NodeS)}]
|
||||||
|
catch _:{node_down, _} -> []
|
||||||
|
end
|
||||||
|
end, Rows);
|
||||||
|
Err ->
|
||||||
|
?ERROR_MSG("failed to select 'muc_online_room': ~p", [Err]),
|
||||||
|
0
|
||||||
|
end.
|
||||||
|
|
||||||
rsm_supported() ->
|
rsm_supported() ->
|
||||||
false.
|
false.
|
||||||
|
|
||||||
register_online_user(_, _, _) ->
|
register_online_user(ServerHost, {U, S, R}, Room, Host) ->
|
||||||
erlang:error(not_implemented).
|
NodeS = erlang:atom_to_binary(node(), latin1),
|
||||||
|
case ?SQL_UPSERT(ServerHost, "muc_online_users",
|
||||||
|
["!username=%(U)s",
|
||||||
|
"!server=%(S)s",
|
||||||
|
"!resource=%(R)s",
|
||||||
|
"!name=%(Room)s",
|
||||||
|
"!host=%(Host)s",
|
||||||
|
"node=%(NodeS)s"]) of
|
||||||
|
ok ->
|
||||||
|
ok;
|
||||||
|
Err ->
|
||||||
|
?ERROR_MSG("failed to update 'muc_online_users': ~p", [Err]),
|
||||||
|
Err
|
||||||
|
end.
|
||||||
|
|
||||||
unregister_online_user(_, _, _) ->
|
unregister_online_user(ServerHost, {U, S, R}, Room, Host) ->
|
||||||
erlang:error(not_implemented).
|
%% TODO: report errors
|
||||||
|
ejabberd_sql:sql_query(
|
||||||
|
ServerHost,
|
||||||
|
?SQL("delete from muc_online_users where username=%(U)s and "
|
||||||
|
"server=%(S)s and resource=%(R)s and name=%(Room)s and "
|
||||||
|
"host=%(Host)s")).
|
||||||
|
|
||||||
count_online_rooms_by_user(_, _) ->
|
count_online_rooms_by_user(ServerHost, U, S) ->
|
||||||
erlang:error(not_implemented).
|
case ejabberd_sql:sql_query(
|
||||||
|
ServerHost,
|
||||||
|
?SQL("select @(count(*))d from muc_online_users where "
|
||||||
|
"username=%(U)s and server=%(S)s")) of
|
||||||
|
{selected, [{Num}]} ->
|
||||||
|
Num;
|
||||||
|
Err ->
|
||||||
|
?ERROR_MSG("failed to select 'muc_online_users': ~p", [Err]),
|
||||||
|
0
|
||||||
|
end.
|
||||||
|
|
||||||
get_online_rooms_by_user(_, _) ->
|
get_online_rooms_by_user(ServerHost, U, S) ->
|
||||||
erlang:error(not_implemented).
|
case ejabberd_sql:sql_query(
|
||||||
|
ServerHost,
|
||||||
|
?SQL("select @(name)s, @(host)s from muc_online_users where "
|
||||||
|
"username=%(U)s and server=%(S)s")) of
|
||||||
|
{selected, Rows} ->
|
||||||
|
Rows;
|
||||||
|
Err ->
|
||||||
|
?ERROR_MSG("failed to select 'muc_online_users': ~p", [Err]),
|
||||||
|
[]
|
||||||
|
end.
|
||||||
|
|
||||||
export(_Server) ->
|
export(_Server) ->
|
||||||
[{muc_room,
|
[{muc_room,
|
||||||
@ -232,3 +328,52 @@ import(_, _, _) ->
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
-spec enc_pid(pid()) -> binary().
|
||||||
|
enc_pid(Pid) ->
|
||||||
|
list_to_binary(erlang:pid_to_list(Pid)).
|
||||||
|
|
||||||
|
-spec dec_pid(binary(), binary()) -> pid().
|
||||||
|
dec_pid(PidBin, NodeBin) ->
|
||||||
|
PidStr = binary_to_list(PidBin),
|
||||||
|
Pid = erlang:list_to_pid(PidStr),
|
||||||
|
case erlang:binary_to_atom(NodeBin, latin1) of
|
||||||
|
Node when Node == node() ->
|
||||||
|
Pid;
|
||||||
|
Node ->
|
||||||
|
try set_node_id(PidStr, NodeBin)
|
||||||
|
catch _:badarg ->
|
||||||
|
erlang:error({node_down, Node})
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
-spec set_node_id(string(), binary()) -> pid().
|
||||||
|
set_node_id(PidStr, NodeBin) ->
|
||||||
|
ExtPidStr = erlang:pid_to_list(
|
||||||
|
binary_to_term(
|
||||||
|
<<131,103,100,(size(NodeBin)):16,NodeBin/binary,0:72>>)),
|
||||||
|
[H|_] = string:tokens(ExtPidStr, "."),
|
||||||
|
[_|T] = string:tokens(PidStr, "."),
|
||||||
|
erlang:list_to_pid(string:join([H|T], ".")).
|
||||||
|
|
||||||
|
clean_tables(ServerHost) ->
|
||||||
|
NodeS = erlang:atom_to_binary(node(), latin1),
|
||||||
|
?INFO_MSG("Cleaning SQL muc_online_room table...", []),
|
||||||
|
case ejabberd_sql:sql_query(
|
||||||
|
ServerHost,
|
||||||
|
?SQL("delete from muc_online_room where node=%(NodeS)s")) of
|
||||||
|
{updated, _} ->
|
||||||
|
ok;
|
||||||
|
Err1 ->
|
||||||
|
?ERROR_MSG("failed to clean 'muc_online_room' table: ~p", [Err1]),
|
||||||
|
Err1
|
||||||
|
end,
|
||||||
|
?INFO_MSG("Cleaning SQL muc_online_users table...", []),
|
||||||
|
case ejabberd_sql:sql_query(
|
||||||
|
ServerHost,
|
||||||
|
?SQL("delete from muc_online_users where node=%(NodeS)s")) of
|
||||||
|
{updated, _} ->
|
||||||
|
ok;
|
||||||
|
Err2 ->
|
||||||
|
?ERROR_MSG("failed to clean 'muc_online_users' table: ~p", [Err2]),
|
||||||
|
Err2
|
||||||
|
end.
|
||||||
|
@ -20,6 +20,7 @@ host_config:
|
|||||||
db_type: sql
|
db_type: sql
|
||||||
mod_muc:
|
mod_muc:
|
||||||
db_type: sql
|
db_type: sql
|
||||||
|
ram_db_type: sql
|
||||||
mod_offline:
|
mod_offline:
|
||||||
db_type: sql
|
db_type: sql
|
||||||
mod_privacy:
|
mod_privacy:
|
||||||
@ -77,6 +78,7 @@ Welcome to this XMPP server."
|
|||||||
db_type: sql
|
db_type: sql
|
||||||
mod_muc:
|
mod_muc:
|
||||||
db_type: sql
|
db_type: sql
|
||||||
|
ram_db_type: sql
|
||||||
mod_offline:
|
mod_offline:
|
||||||
db_type: sql
|
db_type: sql
|
||||||
mod_privacy:
|
mod_privacy:
|
||||||
@ -139,6 +141,7 @@ Welcome to this XMPP server."
|
|||||||
db_type: sql
|
db_type: sql
|
||||||
mod_muc:
|
mod_muc:
|
||||||
db_type: sql
|
db_type: sql
|
||||||
|
ram_db_type: sql
|
||||||
mod_offline:
|
mod_offline:
|
||||||
db_type: sql
|
db_type: sql
|
||||||
mod_privacy:
|
mod_privacy:
|
||||||
|
@ -152,7 +152,7 @@ service_features(Config) ->
|
|||||||
end,
|
end,
|
||||||
RequiredFeatures = sets:from_list(
|
RequiredFeatures = sets:from_list(
|
||||||
[?NS_DISCO_INFO, ?NS_DISCO_ITEMS,
|
[?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]),
|
| MAMFeatures]),
|
||||||
ct:comment("Checking if all needed disco features are set"),
|
ct:comment("Checking if all needed disco features are set"),
|
||||||
|
Loading…
Reference in New Issue
Block a user