mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-22 16:20:52 +01:00
Move functions from roster_versioning to mod_roster (EJAB-964)
SVN Revision: 2431
This commit is contained in:
parent
1b85310f1a
commit
4f6b67b190
@ -310,11 +310,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) ->
|
|||||||
_ ->
|
_ ->
|
||||||
case StateData#state.resource of
|
case StateData#state.resource of
|
||||||
undefined ->
|
undefined ->
|
||||||
RosterVersioningFeature =
|
RosterVersioningFeature = ejabberd_hooks:run_fold(roster_get_versioning_feature, Server, [], [Server]),
|
||||||
case roster_versioning:is_enabled(ServerB) of
|
|
||||||
true -> [roster_versioning:stream_feature()];
|
|
||||||
false -> []
|
|
||||||
end,
|
|
||||||
send_element(
|
send_element(
|
||||||
StateData,
|
StateData,
|
||||||
exmpp_stream:features([
|
exmpp_stream:features([
|
||||||
|
@ -24,6 +24,15 @@
|
|||||||
%%%
|
%%%
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
%%% @doc Roster management (Mnesia storage).
|
||||||
|
%%%
|
||||||
|
%%% Includes support for XEP-0237: Roster Versioning.
|
||||||
|
%%% The roster versioning follows an all-or-nothing strategy:
|
||||||
|
%%% - If the version supplied by the client is the latest, return an empty response.
|
||||||
|
%%% - If not, return the entire new roster (with updated version string).
|
||||||
|
%%% Roster version is a hash digest of the entire roster.
|
||||||
|
%%% No additional data is stored in DB.
|
||||||
|
|
||||||
-module(mod_roster).
|
-module(mod_roster).
|
||||||
-author('alexey@process-one.net').
|
-author('alexey@process-one.net').
|
||||||
|
|
||||||
@ -43,6 +52,7 @@
|
|||||||
item_to_xml/1,
|
item_to_xml/1,
|
||||||
webadmin_page/3,
|
webadmin_page/3,
|
||||||
webadmin_user/4,
|
webadmin_user/4,
|
||||||
|
get_versioning_feature/2,
|
||||||
roster_versioning_enabled/1]).
|
roster_versioning_enabled/1]).
|
||||||
|
|
||||||
-include_lib("exmpp/include/exmpp.hrl").
|
-include_lib("exmpp/include/exmpp.hrl").
|
||||||
@ -52,6 +62,8 @@
|
|||||||
-include("web/ejabberd_http.hrl").
|
-include("web/ejabberd_http.hrl").
|
||||||
-include("web/ejabberd_web_admin.hrl").
|
-include("web/ejabberd_web_admin.hrl").
|
||||||
|
|
||||||
|
-define(NS_ROSTER_VER, "urn:xmpp:features:rosterver").
|
||||||
|
|
||||||
%% @type rosteritem() = {roster, USJ, US, Contact_JID, Name, Subscription, Ask, Groups, Askmessage, Xs}
|
%% @type rosteritem() = {roster, USJ, US, Contact_JID, Name, Subscription, Ask, Groups, Askmessage, Xs}
|
||||||
%% USJ = {LUser, LServer, Prepd_Contact_JID}
|
%% USJ = {LUser, LServer, Prepd_Contact_JID}
|
||||||
%% LUser = binary()
|
%% LUser = binary()
|
||||||
@ -96,6 +108,8 @@ start(Host, Opts) when is_list(Host) ->
|
|||||||
?MODULE, remove_user, 50),
|
?MODULE, remove_user, 50),
|
||||||
ejabberd_hooks:add(resend_subscription_requests_hook, HostB,
|
ejabberd_hooks:add(resend_subscription_requests_hook, HostB,
|
||||||
?MODULE, get_in_pending_subscriptions, 50),
|
?MODULE, get_in_pending_subscriptions, 50),
|
||||||
|
ejabberd_hooks:add(roster_get_versioning_feature, HostB,
|
||||||
|
?MODULE, get_versioning_feature, 50),
|
||||||
ejabberd_hooks:add(webadmin_page_host, HostB,
|
ejabberd_hooks:add(webadmin_page_host, HostB,
|
||||||
?MODULE, webadmin_page, 50),
|
?MODULE, webadmin_page, 50),
|
||||||
ejabberd_hooks:add(webadmin_user, HostB,
|
ejabberd_hooks:add(webadmin_user, HostB,
|
||||||
@ -124,6 +138,8 @@ stop(Host) when is_list(Host) ->
|
|||||||
?MODULE, remove_user, 50),
|
?MODULE, remove_user, 50),
|
||||||
ejabberd_hooks:delete(resend_subscription_requests_hook, HostB,
|
ejabberd_hooks:delete(resend_subscription_requests_hook, HostB,
|
||||||
?MODULE, get_in_pending_subscriptions, 50),
|
?MODULE, get_in_pending_subscriptions, 50),
|
||||||
|
ejabberd_hooks:delete(roster_get_versioning_feature, HostB,
|
||||||
|
?MODULE, get_versioning_feature, 50),
|
||||||
ejabberd_hooks:delete(webadmin_page_host, HostB,
|
ejabberd_hooks:delete(webadmin_page_host, HostB,
|
||||||
?MODULE, webadmin_page, 50),
|
?MODULE, webadmin_page, 50),
|
||||||
ejabberd_hooks:delete(webadmin_user, HostB,
|
ejabberd_hooks:delete(webadmin_user, HostB,
|
||||||
@ -131,16 +147,6 @@ stop(Host) when is_list(Host) ->
|
|||||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB,
|
gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB,
|
||||||
?NS_ROSTER).
|
?NS_ROSTER).
|
||||||
|
|
||||||
%% @spec (Host) -> true | false
|
|
||||||
%% @type Host = binary()
|
|
||||||
roster_versioning_enabled(Host) ->
|
|
||||||
gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, versioning, false).
|
|
||||||
|
|
||||||
%% @spec (Host) -> true | false
|
|
||||||
%% @type Host = binary()
|
|
||||||
roster_version_on_db(Host) ->
|
|
||||||
gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, store_current_id, false).
|
|
||||||
|
|
||||||
%% @spec (From, To, IQ_Rec) -> IQ_Result
|
%% @spec (From, To, IQ_Rec) -> IQ_Result
|
||||||
%% From = exmpp_jid:jid()
|
%% From = exmpp_jid:jid()
|
||||||
%% To = exmpp_jid:jid()
|
%% To = exmpp_jid:jid()
|
||||||
@ -176,6 +182,26 @@ roster_hash(Items) ->
|
|||||||
[R#roster{groups = lists:sort(Grs)} ||
|
[R#roster{groups = lists:sort(Grs)} ||
|
||||||
R = #roster{groups = Grs} <- Items]))).
|
R = #roster{groups = Grs} <- Items]))).
|
||||||
|
|
||||||
|
%% @spec (Host) -> true | false
|
||||||
|
%% @type Host = binary()
|
||||||
|
roster_versioning_enabled(Host) ->
|
||||||
|
gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, versioning, false).
|
||||||
|
|
||||||
|
%% @spec (Host) -> true | false
|
||||||
|
%% @type Host = binary()
|
||||||
|
roster_version_on_db(Host) ->
|
||||||
|
gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, store_current_id, false).
|
||||||
|
|
||||||
|
%% Returns a list that may contain an xmlelement with the XEP-237 feature if it's enabled.
|
||||||
|
get_versioning_feature(Acc, Host) ->
|
||||||
|
case roster_versioning_enabled(Host) of
|
||||||
|
true ->
|
||||||
|
Feature = exmpp_xml:element(?NS_ROSTER_VER, 'ver', [],
|
||||||
|
[exmpp_xml:element(?NS_ROSTER_VER, 'optional')]),
|
||||||
|
[Feature | Acc];
|
||||||
|
false -> []
|
||||||
|
end.
|
||||||
|
|
||||||
roster_version(LServer ,LUser) ->
|
roster_version(LServer ,LUser) ->
|
||||||
US = {LUser, LServer},
|
US = {LUser, LServer},
|
||||||
case roster_version_on_db(LServer) of
|
case roster_version_on_db(LServer) of
|
||||||
@ -477,7 +503,7 @@ push_item(User, Server, From, Item)
|
|||||||
|
|
||||||
case roster_versioning_enabled(Server) of
|
case roster_versioning_enabled(Server) of
|
||||||
true ->
|
true ->
|
||||||
roster_versioning:push_item(Server, User, From, Item, roster_version(Server, User));
|
push_item_version(Server, User, From, Item, roster_version(Server, User));
|
||||||
false ->
|
false ->
|
||||||
lists:foreach(fun(Resource) ->
|
lists:foreach(fun(Resource) ->
|
||||||
push_item(User, Server, Resource, From, Item)
|
push_item(User, Server, Resource, From, Item)
|
||||||
@ -504,6 +530,23 @@ push_item(User, Server, Resource, From, Item)
|
|||||||
exmpp_jid:make(User, Server, Resource),
|
exmpp_jid:make(User, Server, Resource),
|
||||||
ResIQ).
|
ResIQ).
|
||||||
|
|
||||||
|
%% @doc Roster push, calculate and include the version attribute.
|
||||||
|
%% TODO: don't push to those who didn't load roster
|
||||||
|
push_item_version(Server, User, From, Item, RosterVersion) ->
|
||||||
|
lists:foreach(fun(Resource) ->
|
||||||
|
push_item_version(User, Server, Resource, From, Item, RosterVersion)
|
||||||
|
end, ejabberd_sm:get_user_resources(User, Server)).
|
||||||
|
|
||||||
|
push_item_version(User, Server, Resource, From, Item, RosterVersion) ->
|
||||||
|
Request = #xmlel{ns = ?NS_ROSTER, name = 'query', attrs = [?XMLATTR('ver', RosterVersion)],
|
||||||
|
children = [mod_roster:item_to_xml(Item)]},
|
||||||
|
ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request,
|
||||||
|
"push" ++ randoms:get_string()),
|
||||||
|
ejabberd_router:route(
|
||||||
|
From,
|
||||||
|
exmpp_jid:make(User, Server, Resource),
|
||||||
|
ResIQ).
|
||||||
|
|
||||||
%% @spec (Ignored, User, Server) -> Subscription_Lists
|
%% @spec (Ignored, User, Server) -> Subscription_Lists
|
||||||
%% Ignored = term()
|
%% Ignored = term()
|
||||||
%% User = binary()
|
%% User = binary()
|
||||||
|
@ -24,6 +24,15 @@
|
|||||||
%%%
|
%%%
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
%%% @doc Roster management (Mnesia storage).
|
||||||
|
%%%
|
||||||
|
%%% Includes support for XEP-0237: Roster Versioning.
|
||||||
|
%%% The roster versioning follows an all-or-nothing strategy:
|
||||||
|
%%% - If the version supplied by the client is the latest, return an empty response.
|
||||||
|
%%% - If not, return the entire new roster (with updated version string).
|
||||||
|
%%% Roster version is a hash digest of the entire roster.
|
||||||
|
%%% No additional data is stored in DB.
|
||||||
|
|
||||||
-module(mod_roster_odbc).
|
-module(mod_roster_odbc).
|
||||||
-author('alexey@process-one.net').
|
-author('alexey@process-one.net').
|
||||||
|
|
||||||
@ -42,6 +51,7 @@
|
|||||||
get_jid_info/4,
|
get_jid_info/4,
|
||||||
webadmin_page/3,
|
webadmin_page/3,
|
||||||
webadmin_user/4,
|
webadmin_user/4,
|
||||||
|
get_versioning_feature/2,
|
||||||
roster_versioning_enabled/1]).
|
roster_versioning_enabled/1]).
|
||||||
|
|
||||||
-include_lib("exmpp/include/exmpp.hrl").
|
-include_lib("exmpp/include/exmpp.hrl").
|
||||||
@ -51,6 +61,7 @@
|
|||||||
-include("web/ejabberd_http.hrl").
|
-include("web/ejabberd_http.hrl").
|
||||||
-include("web/ejabberd_web_admin.hrl").
|
-include("web/ejabberd_web_admin.hrl").
|
||||||
|
|
||||||
|
-define(NS_ROSTER_VER, "urn:xmpp:features:rosterver").
|
||||||
|
|
||||||
start(Host, Opts) ->
|
start(Host, Opts) ->
|
||||||
HostB = list_to_binary(Host),
|
HostB = list_to_binary(Host),
|
||||||
@ -71,6 +82,8 @@ start(Host, Opts) ->
|
|||||||
?MODULE, remove_user, 50),
|
?MODULE, remove_user, 50),
|
||||||
ejabberd_hooks:add(resend_subscription_requests_hook, HostB,
|
ejabberd_hooks:add(resend_subscription_requests_hook, HostB,
|
||||||
?MODULE, get_in_pending_subscriptions, 50),
|
?MODULE, get_in_pending_subscriptions, 50),
|
||||||
|
ejabberd_hooks:add(roster_get_versioning_feature, HostB,
|
||||||
|
?MODULE, get_versioning_feature, 50),
|
||||||
ejabberd_hooks:add(webadmin_page_host, HostB,
|
ejabberd_hooks:add(webadmin_page_host, HostB,
|
||||||
?MODULE, webadmin_page, 50),
|
?MODULE, webadmin_page, 50),
|
||||||
ejabberd_hooks:add(webadmin_user, HostB,
|
ejabberd_hooks:add(webadmin_user, HostB,
|
||||||
@ -96,6 +109,8 @@ stop(Host) ->
|
|||||||
?MODULE, remove_user, 50),
|
?MODULE, remove_user, 50),
|
||||||
ejabberd_hooks:delete(resend_subscription_requests_hook, HostB,
|
ejabberd_hooks:delete(resend_subscription_requests_hook, HostB,
|
||||||
?MODULE, get_in_pending_subscriptions, 50),
|
?MODULE, get_in_pending_subscriptions, 50),
|
||||||
|
ejabberd_hooks:delete(roster_get_versioning_feature, HostB,
|
||||||
|
?MODULE, get_versioning_feature, 50),
|
||||||
ejabberd_hooks:delete(webadmin_page_host, HostB,
|
ejabberd_hooks:delete(webadmin_page_host, HostB,
|
||||||
?MODULE, webadmin_page, 50),
|
?MODULE, webadmin_page, 50),
|
||||||
ejabberd_hooks:delete(webadmin_user, HostB,
|
ejabberd_hooks:delete(webadmin_user, HostB,
|
||||||
@ -103,12 +118,6 @@ stop(Host) ->
|
|||||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_ROSTER).
|
gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_ROSTER).
|
||||||
|
|
||||||
|
|
||||||
roster_versioning_enabled(Host) ->
|
|
||||||
gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, versioning, false).
|
|
||||||
|
|
||||||
roster_version_on_db(Host) ->
|
|
||||||
gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, store_current_id, false).
|
|
||||||
|
|
||||||
process_iq(From, To, IQ_Rec) ->
|
process_iq(From, To, IQ_Rec) ->
|
||||||
LServer = exmpp_jid:prep_domain_as_list(From),
|
LServer = exmpp_jid:prep_domain_as_list(From),
|
||||||
case lists:member(LServer, ?MYHOSTS) of
|
case lists:member(LServer, ?MYHOSTS) of
|
||||||
@ -131,6 +140,26 @@ roster_hash(Items) ->
|
|||||||
[R#roster{groups = lists:sort(Grs)} ||
|
[R#roster{groups = lists:sort(Grs)} ||
|
||||||
R = #roster{groups = Grs} <- Items]))).
|
R = #roster{groups = Grs} <- Items]))).
|
||||||
|
|
||||||
|
%% @spec (Host) -> true | false
|
||||||
|
%% @type Host = binary()
|
||||||
|
roster_versioning_enabled(Host) ->
|
||||||
|
gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, versioning, false).
|
||||||
|
|
||||||
|
%% @spec (Host) -> true | false
|
||||||
|
%% @type Host = binary()
|
||||||
|
roster_version_on_db(Host) ->
|
||||||
|
gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, store_current_id, false).
|
||||||
|
|
||||||
|
%% Returns a list that may contain an xmlelement with the XEP-237 feature if it's enabled.
|
||||||
|
get_versioning_feature(Acc, Host) ->
|
||||||
|
case roster_versioning_enabled(Host) of
|
||||||
|
true ->
|
||||||
|
Feature = exmpp_xml:element(?NS_ROSTER_VER, 'ver', [],
|
||||||
|
[exmpp_xml:element(?NS_ROSTER_VER, 'optional')]),
|
||||||
|
[Feature | Acc];
|
||||||
|
false -> []
|
||||||
|
end.
|
||||||
|
|
||||||
roster_version(LServer ,LUser) ->
|
roster_version(LServer ,LUser) ->
|
||||||
US = {LUser, LServer},
|
US = {LUser, LServer},
|
||||||
case roster_version_on_db(LServer) of
|
case roster_version_on_db(LServer) of
|
||||||
@ -433,7 +462,7 @@ push_item(User, Server, From, Item) when is_binary(User), is_binary(Server) ->
|
|||||||
Item#roster.subscription}]}),
|
Item#roster.subscription}]}),
|
||||||
case roster_versioning_enabled(Server) of
|
case roster_versioning_enabled(Server) of
|
||||||
true ->
|
true ->
|
||||||
roster_versioning:push_item(Server, User, From, Item, roster_version(Server, User));
|
push_item_version(Server, User, From, Item, roster_version(Server, User));
|
||||||
false ->
|
false ->
|
||||||
lists:foreach(fun(Resource) ->
|
lists:foreach(fun(Resource) ->
|
||||||
push_item(User, Server, Resource, From, Item)
|
push_item(User, Server, Resource, From, Item)
|
||||||
@ -452,6 +481,23 @@ push_item(User, Server, Resource, From, Item) ->
|
|||||||
exmpp_jid:make(User, Server, Resource),
|
exmpp_jid:make(User, Server, Resource),
|
||||||
ResIQ).
|
ResIQ).
|
||||||
|
|
||||||
|
%% @doc Roster push, calculate and include the version attribute.
|
||||||
|
%% TODO: don't push to those who didn't load roster
|
||||||
|
push_item_version(Server, User, From, Item, RosterVersion) ->
|
||||||
|
lists:foreach(fun(Resource) ->
|
||||||
|
push_item_version(User, Server, Resource, From, Item, RosterVersion)
|
||||||
|
end, ejabberd_sm:get_user_resources(User, Server)).
|
||||||
|
|
||||||
|
push_item_version(User, Server, Resource, From, Item, RosterVersion) ->
|
||||||
|
Request = #xmlel{ns = ?NS_ROSTER, name = 'query', attrs = [?XMLATTR('ver', RosterVersion)],
|
||||||
|
children = [mod_roster:item_to_xml(Item)]},
|
||||||
|
ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request,
|
||||||
|
"push" ++ randoms:get_string()),
|
||||||
|
ejabberd_router:route(
|
||||||
|
From,
|
||||||
|
exmpp_jid:make(User, Server, Resource),
|
||||||
|
ResIQ).
|
||||||
|
|
||||||
get_subscription_lists(_, User, Server)
|
get_subscription_lists(_, User, Server)
|
||||||
when is_binary(User), is_binary(Server) ->
|
when is_binary(User), is_binary(Server) ->
|
||||||
try
|
try
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%% File : mod_roster.erl
|
|
||||||
%%% Author : Pablo Polvorin <pablo.polvorin@process-one.net>
|
|
||||||
%%% Purpose : Common utility functions for XEP-0237 (Roster Versioning)
|
|
||||||
%%% Created : 19 Jul 2009 by Pablo Polvorin <pablo.polvorin@process-one.net>
|
|
||||||
%%%
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2009 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., 59 Temple Place, Suite 330, Boston, MA
|
|
||||||
%%% 02111-1307 USA
|
|
||||||
%%%
|
|
||||||
%%%
|
|
||||||
%%% @doc The roster versioning follows an all-or-nothing strategy:
|
|
||||||
%%% - If the version supplied by the client is the lastest, return an empty response
|
|
||||||
%%% - If not, return the entire new roster (with updated version string).
|
|
||||||
%%% Roster version is a hash digest of the entire roster.
|
|
||||||
%%% No additional data is stored in DB.
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
-module(roster_versioning).
|
|
||||||
-author('pablo.polvorin@process-one.net').
|
|
||||||
|
|
||||||
%%API
|
|
||||||
-export([is_enabled/1,
|
|
||||||
stream_feature/0,
|
|
||||||
push_item/5]).
|
|
||||||
|
|
||||||
|
|
||||||
-include("mod_roster.hrl").
|
|
||||||
-include_lib("exmpp/include/exmpp.hrl").
|
|
||||||
|
|
||||||
-define(NS_ROSTER_VER, "urn:xmpp:features:rosterver").
|
|
||||||
|
|
||||||
%%@doc is roster versioning enabled?
|
|
||||||
is_enabled(Host) ->
|
|
||||||
case gen_mod:is_loaded(binary_to_list(Host), mod_roster) of
|
|
||||||
true -> mod_roster:roster_versioning_enabled(Host);
|
|
||||||
false -> mod_roster_odbc:roster_versioning_enabled(Host)
|
|
||||||
end.
|
|
||||||
|
|
||||||
stream_feature() ->
|
|
||||||
exmpp_xml:element(?NS_ROSTER_VER, 'ver', [], [exmpp_xml:element(?NS_ROSTER_VER, 'optional')]).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%% @doc Roster push, calculate and include the version attribute.
|
|
||||||
%% TODO: don't push to those who didn't load roster
|
|
||||||
push_item(Server, User, From, Item, RosterVersion) ->
|
|
||||||
lists:foreach(fun(Resource) ->
|
|
||||||
push_item(User, Server, Resource, From, Item, RosterVersion)
|
|
||||||
end, ejabberd_sm:get_user_resources(User, Server)).
|
|
||||||
|
|
||||||
push_item(User, Server, Resource, From, Item, RosterVersion) ->
|
|
||||||
Request = #xmlel{ns = ?NS_ROSTER, name = 'query', attrs = [?XMLATTR('ver', RosterVersion)],
|
|
||||||
children = [mod_roster:item_to_xml(Item)]},
|
|
||||||
ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request,
|
|
||||||
"push" ++ randoms:get_string()),
|
|
||||||
ejabberd_router:route(
|
|
||||||
From,
|
|
||||||
exmpp_jid:make(User, Server, Resource),
|
|
||||||
ResIQ).
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user