mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
cosmetic cleanup
This commit is contained in:
parent
83dd79a6a7
commit
6aeb9dcb38
@ -19,7 +19,7 @@
|
|||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
-record(request,
|
-record(request,
|
||||||
{method, % :: method(),
|
{method :: method(),
|
||||||
path = [] :: [binary()],
|
path = [] :: [binary()],
|
||||||
q = [] :: [{binary() | nokey, binary()}],
|
q = [] :: [{binary() | nokey, binary()}],
|
||||||
us = {<<>>, <<>>} :: {binary(), binary()},
|
us = {<<>>, <<>>} :: {binary(), binary()},
|
||||||
@ -30,11 +30,10 @@
|
|||||||
ip :: {inet:ip_address(), inet:port_number()},
|
ip :: {inet:ip_address(), inet:port_number()},
|
||||||
host = <<"">> :: binary(),
|
host = <<"">> :: binary(),
|
||||||
port = 5280 :: inet:port_number(),
|
port = 5280 :: inet:port_number(),
|
||||||
tp = http, % :: protocol(),
|
|
||||||
opts = [] :: list(),
|
opts = [] :: list(),
|
||||||
|
tp = http :: protocol(),
|
||||||
headers = [] :: [{atom() | binary(), binary()}]}).
|
headers = [] :: [{atom() | binary(), binary()}]}).
|
||||||
|
|
||||||
|
|
||||||
-record(ws,
|
-record(ws,
|
||||||
{socket :: inet:socket() | p1_tls:tls_socket(),
|
{socket :: inet:socket() | p1_tls:tls_socket(),
|
||||||
sockmod = gen_tcp :: gen_tcp | p1_tls,
|
sockmod = gen_tcp :: gen_tcp | p1_tls,
|
||||||
@ -47,3 +46,7 @@
|
|||||||
q = [] :: [{binary() | nokey, binary()}],
|
q = [] :: [{binary() | nokey, binary()}],
|
||||||
buf :: binary(),
|
buf :: binary(),
|
||||||
http_opts = [] :: list()}).
|
http_opts = [] :: list()}).
|
||||||
|
|
||||||
|
-type method() :: 'GET' | 'HEAD' | 'DELETE' | 'OPTIONS' | 'PUT' | 'POST' | 'TRACE'.
|
||||||
|
-type protocol() :: http | https.
|
||||||
|
-type http_request() :: #request{}.
|
||||||
|
11
include/mod_offline.hrl
Normal file
11
include/mod_offline.hrl
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
-record(offline_msg,
|
||||||
|
{us = {<<"">>, <<"">>} :: {binary(), binary()},
|
||||||
|
timestamp = now() :: erlang:timestamp() | '_',
|
||||||
|
expire = now() :: erlang:timestamp() | never | '_',
|
||||||
|
from = #jid{} :: jid() | '_',
|
||||||
|
to = #jid{} :: jid() | '_',
|
||||||
|
packet = #xmlel{} :: xmlel() | '_'}).
|
||||||
|
|
||||||
|
-record(state,
|
||||||
|
{host = <<"">> :: binary(),
|
||||||
|
access_max_offline_messages}).
|
39
src/acl.erl
39
src/acl.erl
@ -98,7 +98,7 @@ to_record(Host, ACLName, ACLSpec) ->
|
|||||||
-spec add(binary(), aclname(), aclspec()) -> ok | {error, any()}.
|
-spec add(binary(), aclname(), aclspec()) -> ok | {error, any()}.
|
||||||
|
|
||||||
add(Host, ACLName, ACLSpec) ->
|
add(Host, ACLName, ACLSpec) ->
|
||||||
{ResL, BadNodes} = rpc:multicall(mnesia:system_info(running_db_nodes),
|
{ResL, BadNodes} = ejabberd_cluster:multicall(
|
||||||
?MODULE, add_local,
|
?MODULE, add_local,
|
||||||
[Host, ACLName, ACLSpec]),
|
[Host, ACLName, ACLSpec]),
|
||||||
case lists:keyfind(aborted, 1, ResL) of
|
case lists:keyfind(aborted, 1, ResL) of
|
||||||
@ -125,7 +125,7 @@ add_local(Host, ACLName, ACLSpec) ->
|
|||||||
-spec add_list(binary(), [acl()], boolean()) -> ok | {error, any()}.
|
-spec add_list(binary(), [acl()], boolean()) -> ok | {error, any()}.
|
||||||
|
|
||||||
add_list(Host, ACLs, Clear) ->
|
add_list(Host, ACLs, Clear) ->
|
||||||
{ResL, BadNodes} = rpc:multicall(mnesia:system_info(running_db_nodes),
|
{ResL, BadNodes} = ejabberd_cluster:multicall(
|
||||||
?MODULE, add_list_local,
|
?MODULE, add_list_local,
|
||||||
[Host, ACLs, Clear]),
|
[Host, ACLs, Clear]),
|
||||||
case lists:keyfind(aborted, 1, ResL) of
|
case lists:keyfind(aborted, 1, ResL) of
|
||||||
@ -167,16 +167,12 @@ add_list_local(Host, ACLs, Clear) ->
|
|||||||
access_name(), [access_rule()]) -> ok | {error, any()}.
|
access_name(), [access_rule()]) -> ok | {error, any()}.
|
||||||
|
|
||||||
add_access(Host, Access, Rules) ->
|
add_access(Host, Access, Rules) ->
|
||||||
case mnesia:transaction(
|
Obj = #access{name = {Access, Host}, rules = Rules},
|
||||||
fun() ->
|
case mnesia:transaction(fun() -> mnesia:write(Obj) end) of
|
||||||
mnesia:write(
|
{atomic, ok} ->
|
||||||
#access{name = {Access, Host},
|
ok;
|
||||||
rules = Rules})
|
Err ->
|
||||||
end) of
|
{error, Err}
|
||||||
{atomic, ok} ->
|
|
||||||
ok;
|
|
||||||
Err ->
|
|
||||||
{error, Err}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec load_from_config() -> ok.
|
-spec load_from_config() -> ok.
|
||||||
@ -239,8 +235,7 @@ normalize_spec(Spec) ->
|
|||||||
{server_regexp, SR} -> {server_regexp, b(SR)};
|
{server_regexp, SR} -> {server_regexp, b(SR)};
|
||||||
{server_glob, S} -> {server_glob, b(S)};
|
{server_glob, S} -> {server_glob, b(S)};
|
||||||
{resource_glob, R} -> {resource_glob, b(R)};
|
{resource_glob, R} -> {resource_glob, b(R)};
|
||||||
{ip, {Net, Mask}} ->
|
{ip, {Net, Mask}} -> {ip, {Net, Mask}};
|
||||||
{ip, {Net, Mask}};
|
|
||||||
{ip, S} ->
|
{ip, S} ->
|
||||||
case parse_ip_netmask(b(S)) of
|
case parse_ip_netmask(b(S)) of
|
||||||
{ok, Net, Mask} ->
|
{ok, Net, Mask} ->
|
||||||
@ -294,17 +289,15 @@ match_acl(none, _JID, _Host) ->
|
|||||||
match_acl(ACL, IP, Host) when tuple_size(IP) == 4;
|
match_acl(ACL, IP, Host) when tuple_size(IP) == 4;
|
||||||
tuple_size(IP) == 8 ->
|
tuple_size(IP) == 8 ->
|
||||||
lists:any(
|
lists:any(
|
||||||
fun(#acl{aclspec = {ip, {Net, Mask}}}) ->
|
fun({ip, {Net, Mask}}) ->
|
||||||
is_ip_match(IP, Net, Mask);
|
is_ip_match(IP, Net, Mask);
|
||||||
(_) ->
|
(_) ->
|
||||||
false
|
false
|
||||||
end,
|
end, get_aclspecs(ACL, Host));
|
||||||
ets:lookup(acl, {ACL, Host}) ++
|
|
||||||
ets:lookup(acl, {ACL, global}));
|
|
||||||
match_acl(ACL, JID, Host) ->
|
match_acl(ACL, JID, Host) ->
|
||||||
{User, Server, Resource} = jlib:jid_tolower(JID),
|
{User, Server, Resource} = jlib:jid_tolower(JID),
|
||||||
lists:any(
|
lists:any(
|
||||||
fun(#acl{aclspec = Spec}) ->
|
fun(Spec) ->
|
||||||
case Spec of
|
case Spec of
|
||||||
all -> true;
|
all -> true;
|
||||||
{user, {U, S}} -> U == User andalso S == Server;
|
{user, {U, S}} -> U == User andalso S == Server;
|
||||||
@ -350,7 +343,13 @@ match_acl(ACL, JID, Host) ->
|
|||||||
false
|
false
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
ets:lookup(acl, {ACL, Host}) ++
|
get_aclspecs(ACL, Host)).
|
||||||
|
|
||||||
|
get_aclspecs(ACL, Host) ->
|
||||||
|
lists:flatmap(
|
||||||
|
fun(#acl{aclspec = Specs}) ->
|
||||||
|
Specs
|
||||||
|
end, ets:lookup(acl, {ACL, Host}) ++
|
||||||
ets:lookup(acl, {ACL, global})).
|
ets:lookup(acl, {ACL, global})).
|
||||||
|
|
||||||
is_regexp_match(String, RegExp) ->
|
is_regexp_match(String, RegExp) ->
|
||||||
|
@ -462,7 +462,7 @@ restore_mnesia(Path) ->
|
|||||||
|
|
||||||
%% Mnesia database restore
|
%% Mnesia database restore
|
||||||
%% This function is called from ejabberd_ctl, ejabberd_web_admin and
|
%% This function is called from ejabberd_ctl, ejabberd_web_admin and
|
||||||
%% mod_configure/adhoc
|
%% mod_configure/adhoc
|
||||||
restore(Path) ->
|
restore(Path) ->
|
||||||
mnesia:restore(Path, [{keep_tables,keep_tables()},
|
mnesia:restore(Path, [{keep_tables,keep_tables()},
|
||||||
{default_op, skip_tables}]).
|
{default_op, skip_tables}]).
|
||||||
@ -477,7 +477,7 @@ keep_tables() ->
|
|||||||
|
|
||||||
%% Returns the list of modules tables in use, according to the list of actually
|
%% Returns the list of modules tables in use, according to the list of actually
|
||||||
%% loaded modules
|
%% loaded modules
|
||||||
keep_modules_tables() ->
|
keep_modules_tables() ->
|
||||||
lists:map(fun(Module) -> module_tables(Module) end,
|
lists:map(fun(Module) -> module_tables(Module) end,
|
||||||
gen_mod:loaded_modules(?MYNAME)).
|
gen_mod:loaded_modules(?MYNAME)).
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@
|
|||||||
-callback get_password_s(binary(), binary()) -> binary() | {binary(), binary(), binary(), integer()}.
|
-callback get_password_s(binary(), binary()) -> binary() | {binary(), binary(), binary(), integer()}.
|
||||||
|
|
||||||
start() ->
|
start() ->
|
||||||
%% This is only executed by ejabberd_c2s for non-SASL auth client
|
%% This is only executed by ejabberd_c2s for non-SASL auth client
|
||||||
lists:foreach(fun (Host) ->
|
lists:foreach(fun (Host) ->
|
||||||
lists:foreach(fun (M) -> M:start(Host) end,
|
lists:foreach(fun (M) -> M:start(Host) end,
|
||||||
auth_modules(Host))
|
auth_modules(Host))
|
||||||
@ -187,7 +187,8 @@ try_register(User, Server, Password) ->
|
|||||||
case is_user_exists(User, Server) of
|
case is_user_exists(User, Server) of
|
||||||
true -> {atomic, exists};
|
true -> {atomic, exists};
|
||||||
false ->
|
false ->
|
||||||
case lists:member(jlib:nameprep(Server), ?MYHOSTS) of
|
LServer = jlib:nameprep(Server),
|
||||||
|
case lists:member(LServer, ?MYHOSTS) of
|
||||||
true ->
|
true ->
|
||||||
Res = lists:foldl(fun (_M, {atomic, ok} = Res) -> Res;
|
Res = lists:foldl(fun (_M, {atomic, ok} = Res) -> Res;
|
||||||
(M, _) ->
|
(M, _) ->
|
||||||
|
@ -281,7 +281,6 @@ is_fresh_enough(TimeStampLast, CacheTime) ->
|
|||||||
get_last_access(User, Server) ->
|
get_last_access(User, Server) ->
|
||||||
case ejabberd_sm:get_user_resources(User, Server) of
|
case ejabberd_sm:get_user_resources(User, Server) of
|
||||||
[] ->
|
[] ->
|
||||||
%% _US = {User, Server},
|
|
||||||
case get_last_info(User, Server) of
|
case get_last_info(User, Server) of
|
||||||
mod_last_required -> mod_last_required;
|
mod_last_required -> mod_last_required;
|
||||||
not_found -> never;
|
not_found -> never;
|
||||||
|
@ -203,8 +203,9 @@ start(SockData, Opts) ->
|
|||||||
?SUPERVISOR_START.
|
?SUPERVISOR_START.
|
||||||
|
|
||||||
start_link(SockData, Opts) ->
|
start_link(SockData, Opts) ->
|
||||||
?GEN_FSM:start_link(ejabberd_c2s, [SockData, Opts],
|
(?GEN_FSM):start_link(ejabberd_c2s,
|
||||||
fsm_limit_opts(Opts) ++ ?FSMOPTS).
|
[SockData, Opts],
|
||||||
|
fsm_limit_opts(Opts) ++ ?FSMOPTS).
|
||||||
|
|
||||||
socket_type() -> xml_stream.
|
socket_type() -> xml_stream.
|
||||||
|
|
||||||
@ -256,13 +257,6 @@ stop(FsmRef) -> (?GEN_FSM):send_event(FsmRef, closed).
|
|||||||
%%% Callback functions from gen_fsm
|
%%% Callback functions from gen_fsm
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: init/1
|
|
||||||
%% Returns: {ok, StateName, StateData} |
|
|
||||||
%% {ok, StateName, StateData, Timeout} |
|
|
||||||
%% ignore |
|
|
||||||
%% {stop, StopReason}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
init([{SockMod, Socket}, Opts]) ->
|
init([{SockMod, Socket}, Opts]) ->
|
||||||
Access = case lists:keysearch(access, 1, Opts) of
|
Access = case lists:keysearch(access, 1, Opts) of
|
||||||
{value, {_, A}} -> A;
|
{value, {_, A}} -> A;
|
||||||
@ -350,36 +344,29 @@ get_subscribed(FsmRef) ->
|
|||||||
(?GEN_FSM):sync_send_all_state_event(FsmRef,
|
(?GEN_FSM):sync_send_all_state_event(FsmRef,
|
||||||
get_subscribed, 1000).
|
get_subscribed, 1000).
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: StateName/2
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||||
DefaultLang = ?MYLANG,
|
DefaultLang = ?MYLANG,
|
||||||
case xml:get_attr_s(<<"xmlns:stream">>, Attrs) of
|
case xml:get_attr_s(<<"xmlns:stream">>, Attrs) of
|
||||||
?NS_STREAM ->
|
?NS_STREAM ->
|
||||||
Server =
|
Server =
|
||||||
case StateData#state.server of
|
case StateData#state.server of
|
||||||
<<"">> ->
|
<<"">> ->
|
||||||
jlib:nameprep(xml:get_attr_s(<<"to">>, Attrs));
|
jlib:nameprep(xml:get_attr_s(<<"to">>, Attrs));
|
||||||
S -> S
|
S -> S
|
||||||
end,
|
end,
|
||||||
Lang = case xml:get_attr_s(<<"xml:lang">>, Attrs) of
|
Lang = case xml:get_attr_s(<<"xml:lang">>, Attrs) of
|
||||||
Lang1 when byte_size(Lang1) =< 35 ->
|
Lang1 when byte_size(Lang1) =< 35 ->
|
||||||
%% As stated in BCP47, 4.4.1:
|
%% As stated in BCP47, 4.4.1:
|
||||||
%% Protocols or specifications that
|
%% Protocols or specifications that
|
||||||
%% specify limited buffer sizes for
|
%% specify limited buffer sizes for
|
||||||
%% language tags MUST allow for
|
%% language tags MUST allow for
|
||||||
%% language tags of at least 35 characters.
|
%% language tags of at least 35 characters.
|
||||||
Lang1;
|
Lang1;
|
||||||
_ ->
|
_ ->
|
||||||
%% Do not store long language tag to
|
%% Do not store long language tag to
|
||||||
%% avoid possible DoS/flood attacks
|
%% avoid possible DoS/flood attacks
|
||||||
<<"">>
|
<<"">>
|
||||||
end,
|
end,
|
||||||
IsBlacklistedIP = is_ip_blacklisted(StateData#state.ip, Lang),
|
IsBlacklistedIP = is_ip_blacklisted(StateData#state.ip, Lang),
|
||||||
case lists:member(Server, ?MYHOSTS) of
|
case lists:member(Server, ?MYHOSTS) of
|
||||||
true when IsBlacklistedIP == false ->
|
true when IsBlacklistedIP == false ->
|
||||||
@ -392,168 +379,162 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
TLS = StateData#state.tls,
|
TLS = StateData#state.tls,
|
||||||
TLSEnabled = StateData#state.tls_enabled,
|
TLSEnabled = StateData#state.tls_enabled,
|
||||||
TLSRequired = StateData#state.tls_required,
|
TLSRequired = StateData#state.tls_required,
|
||||||
SASLState =
|
SASLState = cyrsasl:server_new(
|
||||||
cyrsasl:server_new(
|
<<"jabber">>, Server, <<"">>, [],
|
||||||
<<"jabber">>, Server, <<"">>, [],
|
fun (U) ->
|
||||||
fun(U) ->
|
ejabberd_auth:get_password_with_authmodule(
|
||||||
ejabberd_auth:get_password_with_authmodule(
|
U, Server)
|
||||||
U, Server)
|
end,
|
||||||
end,
|
fun (U, P) ->
|
||||||
fun(U, P) ->
|
ejabberd_auth:check_password_with_authmodule(
|
||||||
ejabberd_auth:check_password_with_authmodule(
|
U, Server, P)
|
||||||
U, Server, P)
|
end,
|
||||||
end,
|
fun (U, P, D, DG) ->
|
||||||
fun(U, P, D, DG) ->
|
ejabberd_auth:check_password_with_authmodule(
|
||||||
ejabberd_auth:check_password_with_authmodule(
|
U, Server, P, D, DG)
|
||||||
U, Server, P, D, DG)
|
end),
|
||||||
end),
|
|
||||||
Mechs =
|
Mechs =
|
||||||
case TLSEnabled or not TLSRequired of
|
case TLSEnabled or not TLSRequired of
|
||||||
true ->
|
true ->
|
||||||
Ms = lists:map(fun (S) ->
|
Ms = lists:map(fun (S) ->
|
||||||
#xmlel{name = <<"mechanism">>,
|
#xmlel{name = <<"mechanism">>,
|
||||||
attrs = [],
|
attrs = [],
|
||||||
children = [{xmlcdata, S}]}
|
children = [{xmlcdata, S}]}
|
||||||
end,
|
end,
|
||||||
cyrsasl:listmech(Server)),
|
cyrsasl:listmech(Server)),
|
||||||
[#xmlel{name = <<"mechanisms">>,
|
[#xmlel{name = <<"mechanisms">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_SASL}],
|
attrs = [{<<"xmlns">>, ?NS_SASL}],
|
||||||
children = Ms}];
|
children = Ms}];
|
||||||
false ->
|
false ->
|
||||||
[]
|
[]
|
||||||
end,
|
end,
|
||||||
SockMod =
|
SockMod =
|
||||||
(StateData#state.sockmod):get_sockmod(
|
(StateData#state.sockmod):get_sockmod(StateData#state.socket),
|
||||||
StateData#state.socket),
|
|
||||||
Zlib = StateData#state.zlib,
|
Zlib = StateData#state.zlib,
|
||||||
CompressFeature =
|
CompressFeature = case Zlib andalso
|
||||||
case Zlib andalso
|
((SockMod == gen_tcp) orelse (SockMod == p1_tls)) of
|
||||||
((SockMod == gen_tcp) orelse
|
true ->
|
||||||
(SockMod == p1_tls)) of
|
[#xmlel{name = <<"compression">>,
|
||||||
true ->
|
attrs = [{<<"xmlns">>, ?NS_FEATURE_COMPRESS}],
|
||||||
[#xmlel{name = <<"compression">>,
|
children = [#xmlel{name = <<"method">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_FEATURE_COMPRESS}],
|
attrs = [],
|
||||||
children = [#xmlel{name = <<"method">>,
|
children = [{xmlcdata, <<"zlib">>}]}]}];
|
||||||
attrs = [],
|
_ ->
|
||||||
children = [{xmlcdata, <<"zlib">>}]}]}];
|
[]
|
||||||
_ ->
|
end,
|
||||||
[]
|
|
||||||
end,
|
|
||||||
TLSFeature =
|
TLSFeature =
|
||||||
case (TLS == true) andalso
|
case (TLS == true) andalso
|
||||||
(TLSEnabled == false) andalso
|
(TLSEnabled == false) andalso
|
||||||
(SockMod == gen_tcp) of
|
(SockMod == gen_tcp) of
|
||||||
true ->
|
true ->
|
||||||
case TLSRequired of
|
case TLSRequired of
|
||||||
true ->
|
true ->
|
||||||
[#xmlel{name = <<"starttls">>,
|
[#xmlel{name = <<"starttls">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_TLS}],
|
attrs = [{<<"xmlns">>, ?NS_TLS}],
|
||||||
children = [#xmlel{name = <<"required">>,
|
children = [#xmlel{name = <<"required">>,
|
||||||
attrs = [],
|
attrs = [],
|
||||||
children = []}]}];
|
children = []}]}];
|
||||||
_ ->
|
_ ->
|
||||||
[#xmlel{name = <<"starttls">>,
|
[#xmlel{name = <<"starttls">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_TLS}],
|
attrs = [{<<"xmlns">>, ?NS_TLS}],
|
||||||
children = []}]
|
children = []}]
|
||||||
end;
|
end;
|
||||||
false ->
|
false ->
|
||||||
[]
|
[]
|
||||||
end,
|
end,
|
||||||
StreamFeatures1 = TLSFeature ++ CompressFeature ++ Mechs,
|
StreamFeatures1 = TLSFeature ++ CompressFeature ++ Mechs,
|
||||||
StreamFeatures = ejabberd_hooks:run_fold(c2s_stream_features,
|
StreamFeatures = ejabberd_hooks:run_fold(c2s_stream_features,
|
||||||
Server, StreamFeatures1, [Server]),
|
Server, StreamFeatures1, [Server]),
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
#xmlel{name = <<"stream:features">>,
|
#xmlel{name = <<"stream:features">>,
|
||||||
attrs = [],
|
attrs = [],
|
||||||
children =
|
children = StreamFeatures}),
|
||||||
StreamFeatures}),
|
|
||||||
fsm_next_state(wait_for_feature_request,
|
fsm_next_state(wait_for_feature_request,
|
||||||
StateData#state{
|
StateData#state{server = Server,
|
||||||
server = Server,
|
sasl_state = SASLState,
|
||||||
sasl_state = SASLState,
|
lang = Lang});
|
||||||
lang = Lang});
|
|
||||||
_ ->
|
_ ->
|
||||||
case StateData#state.resource of
|
case StateData#state.resource of
|
||||||
<<"">> ->
|
<<"">> ->
|
||||||
RosterVersioningFeature =
|
RosterVersioningFeature =
|
||||||
ejabberd_hooks:run_fold(roster_get_versioning_feature,
|
ejabberd_hooks:run_fold(roster_get_versioning_feature,
|
||||||
Server, [],
|
Server, [],
|
||||||
[Server]),
|
[Server]),
|
||||||
StreamManagementFeature =
|
StreamManagementFeature =
|
||||||
case stream_mgmt_enabled(StateData) of
|
case stream_mgmt_enabled(StateData) of
|
||||||
true ->
|
true ->
|
||||||
[#xmlel{name = <<"sm">>,
|
[#xmlel{name = <<"sm">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_STREAM_MGMT_2}],
|
attrs = [{<<"xmlns">>, ?NS_STREAM_MGMT_2}],
|
||||||
children = []},
|
children = []},
|
||||||
#xmlel{name = <<"sm">>,
|
#xmlel{name = <<"sm">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_STREAM_MGMT_3}],
|
attrs = [{<<"xmlns">>, ?NS_STREAM_MGMT_3}],
|
||||||
children = []}];
|
children = []}];
|
||||||
false ->
|
false ->
|
||||||
[]
|
[]
|
||||||
end,
|
end,
|
||||||
StreamFeatures1 = [#xmlel{name = <<"bind">>,
|
StreamFeatures1 = [#xmlel{name = <<"bind">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_BIND}],
|
attrs = [{<<"xmlns">>, ?NS_BIND}],
|
||||||
children = []},
|
children = []},
|
||||||
#xmlel{name = <<"session">>,
|
#xmlel{name = <<"session">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_SESSION}],
|
attrs = [{<<"xmlns">>, ?NS_SESSION}],
|
||||||
children = []}]
|
children = []}]
|
||||||
++
|
++
|
||||||
RosterVersioningFeature ++
|
RosterVersioningFeature ++
|
||||||
StreamManagementFeature ++
|
StreamManagementFeature ++
|
||||||
ejabberd_hooks:run_fold(c2s_post_auth_features,
|
ejabberd_hooks:run_fold(c2s_post_auth_features,
|
||||||
Server, [], [Server]),
|
Server, [], [Server]),
|
||||||
StreamFeatures = ejabberd_hooks:run_fold(c2s_stream_features,
|
StreamFeatures = ejabberd_hooks:run_fold(c2s_stream_features,
|
||||||
Server, StreamFeatures1, [Server]),
|
Server, StreamFeatures1, [Server]),
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
#xmlel{name = <<"stream:features">>,
|
#xmlel{name = <<"stream:features">>,
|
||||||
attrs = [],
|
attrs = [],
|
||||||
children = StreamFeatures}),
|
children = StreamFeatures}),
|
||||||
fsm_next_state(wait_for_bind,
|
fsm_next_state(wait_for_bind,
|
||||||
StateData#state{server = Server, lang = Lang});
|
StateData#state{server = Server, lang = Lang});
|
||||||
_ ->
|
_ ->
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
#xmlel{name = <<"stream:features">>,
|
#xmlel{name = <<"stream:features">>,
|
||||||
attrs = [],
|
attrs = [],
|
||||||
children = []}),
|
children = []}),
|
||||||
fsm_next_state(wait_for_session,
|
fsm_next_state(wait_for_session,
|
||||||
StateData#state{server = Server, lang = Lang})
|
StateData#state{server = Server, lang = Lang})
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
send_header(StateData, Server, <<"">>, DefaultLang),
|
send_header(StateData, Server, <<"">>, DefaultLang),
|
||||||
if not StateData#state.tls_enabled and
|
if not StateData#state.tls_enabled and
|
||||||
StateData#state.tls_required ->
|
StateData#state.tls_required ->
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
?POLICY_VIOLATION_ERR(Lang,
|
?POLICY_VIOLATION_ERR(Lang,
|
||||||
<<"Use of STARTTLS required">>)),
|
<<"Use of STARTTLS required">>)),
|
||||||
send_trailer(StateData),
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
true ->
|
true ->
|
||||||
fsm_next_state(wait_for_auth,
|
fsm_next_state(wait_for_auth,
|
||||||
StateData#state{server = Server,
|
StateData#state{server = Server,
|
||||||
lang = Lang})
|
lang = Lang})
|
||||||
end
|
end
|
||||||
|
end;
|
||||||
|
true ->
|
||||||
|
IP = StateData#state.ip,
|
||||||
|
{true, LogReason, ReasonT} = IsBlacklistedIP,
|
||||||
|
?INFO_MSG("Connection attempt from blacklisted IP ~s: ~s",
|
||||||
|
[jlib:ip_to_list(IP), LogReason]),
|
||||||
|
send_header(StateData, Server, <<"">>, DefaultLang),
|
||||||
|
send_element(StateData, ?POLICY_VIOLATION_ERR(Lang, ReasonT)),
|
||||||
|
send_trailer(StateData),
|
||||||
|
{stop, normal, StateData};
|
||||||
|
_ ->
|
||||||
|
send_header(StateData, ?MYNAME, <<"">>, DefaultLang),
|
||||||
|
send_element(StateData, ?HOST_UNKNOWN_ERR),
|
||||||
|
send_trailer(StateData),
|
||||||
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
true ->
|
|
||||||
IP = StateData#state.ip,
|
|
||||||
{true, LogReason, ReasonT} = IsBlacklistedIP,
|
|
||||||
?INFO_MSG("Connection attempt from blacklisted IP ~s: ~s",
|
|
||||||
[jlib:ip_to_list(IP), LogReason]),
|
|
||||||
send_header(StateData, Server, <<"">>, DefaultLang),
|
|
||||||
send_element(StateData, ?POLICY_VIOLATION_ERR(Lang, ReasonT)),
|
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
|
||||||
_ ->
|
_ ->
|
||||||
send_header(StateData, ?MYNAME, <<"">>, DefaultLang),
|
send_header(StateData, ?MYNAME, <<"">>, DefaultLang),
|
||||||
send_element(StateData, ?HOST_UNKNOWN_ERR),
|
send_element(StateData, ?INVALID_NS_ERR),
|
||||||
send_trailer(StateData),
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
|
||||||
_ ->
|
|
||||||
send_header(StateData, ?MYNAME, <<"">>, DefaultLang),
|
|
||||||
send_element(StateData, ?INVALID_NS_ERR),
|
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData}
|
|
||||||
end;
|
end;
|
||||||
wait_for_stream(timeout, StateData) ->
|
wait_for_stream(timeout, StateData) ->
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
@ -574,151 +555,148 @@ wait_for_stream(closed, StateData) ->
|
|||||||
{stop, normal, StateData}.
|
{stop, normal, StateData}.
|
||||||
|
|
||||||
wait_for_auth({xmlstreamelement, #xmlel{name = Name} = El}, StateData)
|
wait_for_auth({xmlstreamelement, #xmlel{name = Name} = El}, StateData)
|
||||||
when ?IS_STREAM_MGMT_TAG(Name) ->
|
when ?IS_STREAM_MGMT_TAG(Name) ->
|
||||||
fsm_next_state(wait_for_auth, dispatch_stream_mgmt(El, StateData));
|
fsm_next_state(wait_for_auth, dispatch_stream_mgmt(El, StateData));
|
||||||
wait_for_auth({xmlstreamelement, El}, StateData) ->
|
wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||||
case is_auth_packet(El) of
|
case is_auth_packet(El) of
|
||||||
{auth, _ID, get, {U, _, _, _}} ->
|
{auth, _ID, get, {U, _, _, _}} ->
|
||||||
#xmlel{name = Name, attrs = Attrs} =
|
#xmlel{name = Name, attrs = Attrs} = jlib:make_result_iq_reply(El),
|
||||||
jlib:make_result_iq_reply(El),
|
case U of
|
||||||
case U of
|
<<"">> -> UCdata = [];
|
||||||
<<"">> -> UCdata = [];
|
_ -> UCdata = [{xmlcdata, U}]
|
||||||
_ -> UCdata = [{xmlcdata, U}]
|
end,
|
||||||
end,
|
Res = case
|
||||||
Res = case
|
ejabberd_auth:plain_password_required(StateData#state.server)
|
||||||
ejabberd_auth:plain_password_required(StateData#state.server)
|
of
|
||||||
|
false ->
|
||||||
|
#xmlel{name = Name, attrs = Attrs,
|
||||||
|
children =
|
||||||
|
[#xmlel{name = <<"query">>,
|
||||||
|
attrs = [{<<"xmlns">>, ?NS_AUTH}],
|
||||||
|
children =
|
||||||
|
[#xmlel{name = <<"username">>,
|
||||||
|
attrs = [],
|
||||||
|
children = UCdata},
|
||||||
|
#xmlel{name = <<"password">>,
|
||||||
|
attrs = [], children = []},
|
||||||
|
#xmlel{name = <<"digest">>,
|
||||||
|
attrs = [], children = []},
|
||||||
|
#xmlel{name = <<"resource">>,
|
||||||
|
attrs = [],
|
||||||
|
children = []}]}]};
|
||||||
|
true ->
|
||||||
|
#xmlel{name = Name, attrs = Attrs,
|
||||||
|
children =
|
||||||
|
[#xmlel{name = <<"query">>,
|
||||||
|
attrs = [{<<"xmlns">>, ?NS_AUTH}],
|
||||||
|
children =
|
||||||
|
[#xmlel{name = <<"username">>,
|
||||||
|
attrs = [],
|
||||||
|
children = UCdata},
|
||||||
|
#xmlel{name = <<"password">>,
|
||||||
|
attrs = [], children = []},
|
||||||
|
#xmlel{name = <<"resource">>,
|
||||||
|
attrs = [],
|
||||||
|
children = []}]}]}
|
||||||
|
end,
|
||||||
|
send_element(StateData, Res),
|
||||||
|
fsm_next_state(wait_for_auth, StateData);
|
||||||
|
{auth, _ID, set, {_U, _P, _D, <<"">>}} ->
|
||||||
|
Err = jlib:make_error_reply(El,
|
||||||
|
?ERR_AUTH_NO_RESOURCE_PROVIDED((StateData#state.lang))),
|
||||||
|
send_element(StateData, Err),
|
||||||
|
fsm_next_state(wait_for_auth, StateData);
|
||||||
|
{auth, _ID, set, {U, P, D, R}} ->
|
||||||
|
JID = jlib:make_jid(U, StateData#state.server, R),
|
||||||
|
case JID /= error andalso
|
||||||
|
acl:match_rule(StateData#state.server,
|
||||||
|
StateData#state.access, JID)
|
||||||
|
== allow
|
||||||
|
of
|
||||||
|
true ->
|
||||||
|
DGen = fun (PW) ->
|
||||||
|
p1_sha:sha(<<(StateData#state.streamid)/binary, PW/binary>>)
|
||||||
|
end,
|
||||||
|
case ejabberd_auth:check_password_with_authmodule(U,
|
||||||
|
StateData#state.server,
|
||||||
|
P, D, DGen)
|
||||||
of
|
of
|
||||||
false ->
|
{true, AuthModule} ->
|
||||||
#xmlel{name = Name, attrs = Attrs,
|
?INFO_MSG("(~w) Accepted legacy authentication for ~s by ~p from ~s",
|
||||||
children =
|
[StateData#state.socket,
|
||||||
[#xmlel{name = <<"query">>,
|
jlib:jid_to_string(JID), AuthModule,
|
||||||
attrs = [{<<"xmlns">>, ?NS_AUTH}],
|
ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]),
|
||||||
children =
|
ejabberd_hooks:run(c2s_auth_result, StateData#state.server,
|
||||||
[#xmlel{name = <<"username">>,
|
[true, U, StateData#state.server,
|
||||||
attrs = [],
|
StateData#state.ip]),
|
||||||
children = UCdata},
|
Conn = get_conn_type(StateData),
|
||||||
#xmlel{name = <<"password">>,
|
Info = [{ip, StateData#state.ip}, {conn, Conn},
|
||||||
attrs = [], children = []},
|
|
||||||
#xmlel{name = <<"digest">>,
|
|
||||||
attrs = [], children = []},
|
|
||||||
#xmlel{name = <<"resource">>,
|
|
||||||
attrs = [],
|
|
||||||
children = []}]}]};
|
|
||||||
true ->
|
|
||||||
#xmlel{name = Name, attrs = Attrs,
|
|
||||||
children =
|
|
||||||
[#xmlel{name = <<"query">>,
|
|
||||||
attrs = [{<<"xmlns">>, ?NS_AUTH}],
|
|
||||||
children =
|
|
||||||
[#xmlel{name = <<"username">>,
|
|
||||||
attrs = [],
|
|
||||||
children = UCdata},
|
|
||||||
#xmlel{name = <<"password">>,
|
|
||||||
attrs = [], children = []},
|
|
||||||
#xmlel{name = <<"resource">>,
|
|
||||||
attrs = [],
|
|
||||||
children = []}]}]}
|
|
||||||
end,
|
|
||||||
send_element(StateData, Res),
|
|
||||||
fsm_next_state(wait_for_auth, StateData);
|
|
||||||
{auth, _ID, set, {_U, _P, _D, <<"">>}} ->
|
|
||||||
Err = jlib:make_error_reply(El,
|
|
||||||
?ERR_AUTH_NO_RESOURCE_PROVIDED((StateData#state.lang))),
|
|
||||||
send_element(StateData, Err),
|
|
||||||
fsm_next_state(wait_for_auth, StateData);
|
|
||||||
{auth, _ID, set, {U, P, D, R}} ->
|
|
||||||
JID = jlib:make_jid(U, StateData#state.server, R),
|
|
||||||
case JID /= error andalso
|
|
||||||
acl:match_rule(StateData#state.server,
|
|
||||||
StateData#state.access, JID)
|
|
||||||
== allow
|
|
||||||
of
|
|
||||||
true ->
|
|
||||||
DGen = fun (PW) ->
|
|
||||||
p1_sha:sha(<<(StateData#state.streamid)/binary, PW/binary>>)
|
|
||||||
end,
|
|
||||||
case ejabberd_auth:check_password_with_authmodule(U,
|
|
||||||
StateData#state.server,
|
|
||||||
P, D, DGen)
|
|
||||||
of
|
|
||||||
{true, AuthModule} ->
|
|
||||||
?INFO_MSG("(~w) Accepted legacy authentication for ~s by ~p from ~s",
|
|
||||||
[StateData#state.socket,
|
|
||||||
jlib:jid_to_string(JID), AuthModule,
|
|
||||||
ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]),
|
|
||||||
ejabberd_hooks:run(c2s_auth_result, StateData#state.server,
|
|
||||||
[true, U, StateData#state.server,
|
|
||||||
StateData#state.ip]),
|
|
||||||
Conn = get_conn_type(StateData),
|
|
||||||
Info = [{ip, StateData#state.ip}, {conn, Conn},
|
|
||||||
{auth_module, AuthModule}],
|
{auth_module, AuthModule}],
|
||||||
Res = jlib:make_result_iq_reply(
|
Res = jlib:make_result_iq_reply(
|
||||||
El#xmlel{children = []}),
|
El#xmlel{children = []}),
|
||||||
send_element(StateData, Res),
|
send_element(StateData, Res),
|
||||||
ejabberd_sm:open_session(StateData#state.sid, U,
|
ejabberd_sm:open_session(StateData#state.sid, U,
|
||||||
StateData#state.server, R,
|
StateData#state.server, R,
|
||||||
Info),
|
Info),
|
||||||
change_shaper(StateData, JID),
|
change_shaper(StateData, JID),
|
||||||
{Fs, Ts} =
|
{Fs, Ts} =
|
||||||
ejabberd_hooks:run_fold(roster_get_subscription_lists,
|
ejabberd_hooks:run_fold(roster_get_subscription_lists,
|
||||||
StateData#state.server,
|
StateData#state.server,
|
||||||
{[], []},
|
{[], []},
|
||||||
[U,
|
[U, StateData#state.server]),
|
||||||
StateData#state.server]),
|
LJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
|
||||||
LJID =
|
Fs1 = [LJID | Fs],
|
||||||
jlib:jid_tolower(jlib:jid_remove_resource(JID)),
|
Ts1 = [LJID | Ts],
|
||||||
Fs1 = [LJID | Fs],
|
PrivList = ejabberd_hooks:run_fold(privacy_get_user_list,
|
||||||
Ts1 = [LJID | Ts],
|
StateData#state.server,
|
||||||
PrivList = ejabberd_hooks:run_fold(privacy_get_user_list,
|
#userlist{},
|
||||||
StateData#state.server,
|
[U, StateData#state.server]),
|
||||||
#userlist{},
|
NewStateData = StateData#state{user = U,
|
||||||
[U, StateData#state.server]),
|
resource = R,
|
||||||
NewStateData = StateData#state{user = U,
|
jid = JID,
|
||||||
resource = R,
|
conn = Conn,
|
||||||
jid = JID,
|
auth_module = AuthModule,
|
||||||
conn = Conn,
|
pres_f = (?SETS):from_list(Fs1),
|
||||||
auth_module = AuthModule,
|
pres_t = (?SETS):from_list(Ts1),
|
||||||
pres_f = (?SETS):from_list(Fs1),
|
privacy_list = PrivList},
|
||||||
pres_t = (?SETS):from_list(Ts1),
|
fsm_next_state(session_established, NewStateData);
|
||||||
privacy_list = PrivList},
|
_ ->
|
||||||
fsm_next_state(session_established, NewStateData);
|
?INFO_MSG("(~w) Failed legacy authentication for ~s from ~s",
|
||||||
_ ->
|
[StateData#state.socket,
|
||||||
?INFO_MSG("(~w) Failed legacy authentication for ~s from ~s",
|
jlib:jid_to_string(JID),
|
||||||
[StateData#state.socket,
|
ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]),
|
||||||
jlib:jid_to_string(JID),
|
ejabberd_hooks:run(c2s_auth_result, StateData#state.server,
|
||||||
ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]),
|
[false, U, StateData#state.server,
|
||||||
ejabberd_hooks:run(c2s_auth_result, StateData#state.server,
|
StateData#state.ip]),
|
||||||
[false, U, StateData#state.server,
|
Err = jlib:make_error_reply(El, ?ERR_NOT_AUTHORIZED),
|
||||||
StateData#state.ip]),
|
send_element(StateData, Err),
|
||||||
Err = jlib:make_error_reply(El, ?ERR_NOT_AUTHORIZED),
|
fsm_next_state(wait_for_auth, StateData)
|
||||||
send_element(StateData, Err),
|
end;
|
||||||
fsm_next_state(wait_for_auth, StateData)
|
_ ->
|
||||||
end;
|
if JID == error ->
|
||||||
_ ->
|
?INFO_MSG("(~w) Forbidden legacy authentication "
|
||||||
if JID == error ->
|
"for username '~s' with resource '~s'",
|
||||||
?INFO_MSG("(~w) Forbidden legacy authentication "
|
[StateData#state.socket, U, R]),
|
||||||
"for username '~s' with resource '~s'",
|
Err = jlib:make_error_reply(El, ?ERR_JID_MALFORMED),
|
||||||
[StateData#state.socket, U, R]),
|
send_element(StateData, Err),
|
||||||
Err = jlib:make_error_reply(El, ?ERR_JID_MALFORMED),
|
fsm_next_state(wait_for_auth, StateData);
|
||||||
send_element(StateData, Err),
|
true ->
|
||||||
fsm_next_state(wait_for_auth, StateData);
|
?INFO_MSG("(~w) Forbidden legacy authentication "
|
||||||
true ->
|
"for ~s from ~s",
|
||||||
?INFO_MSG("(~w) Forbidden legacy authentication "
|
[StateData#state.socket,
|
||||||
"for ~s from ~s",
|
jlib:jid_to_string(JID),
|
||||||
[StateData#state.socket,
|
ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]),
|
||||||
jlib:jid_to_string(JID),
|
ejabberd_hooks:run(c2s_auth_result, StateData#state.server,
|
||||||
ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]),
|
[false, U, StateData#state.server,
|
||||||
ejabberd_hooks:run(c2s_auth_result, StateData#state.server,
|
StateData#state.ip]),
|
||||||
[false, U, StateData#state.server,
|
Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
|
||||||
StateData#state.ip]),
|
send_element(StateData, Err),
|
||||||
Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
|
fsm_next_state(wait_for_auth, StateData)
|
||||||
send_element(StateData, Err),
|
end
|
||||||
fsm_next_state(wait_for_auth, StateData)
|
end;
|
||||||
end
|
_ ->
|
||||||
end;
|
process_unauthenticated_stanza(StateData, El),
|
||||||
_ ->
|
fsm_next_state(wait_for_auth, StateData)
|
||||||
process_unauthenticated_stanza(StateData, El),
|
|
||||||
fsm_next_state(wait_for_auth, StateData)
|
|
||||||
end;
|
end;
|
||||||
wait_for_auth(timeout, StateData) ->
|
wait_for_auth(timeout, StateData) ->
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
@ -786,10 +764,10 @@ wait_for_feature_request({xmlstreamelement, El},
|
|||||||
fsm_next_state(wait_for_sasl_response,
|
fsm_next_state(wait_for_sasl_response,
|
||||||
StateData#state{sasl_state = NewSASLState});
|
StateData#state{sasl_state = NewSASLState});
|
||||||
{error, Error, Username} ->
|
{error, Error, Username} ->
|
||||||
?INFO_MSG("(~w) Failed authentication for ~s@~s from ~s",
|
?INFO_MSG("(~w) Failed authentication for ~s@~s from ~s",
|
||||||
[StateData#state.socket,
|
[StateData#state.socket,
|
||||||
Username, StateData#state.server,
|
Username, StateData#state.server,
|
||||||
ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]),
|
ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]),
|
||||||
ejabberd_hooks:run(c2s_auth_result, StateData#state.server,
|
ejabberd_hooks:run(c2s_auth_result, StateData#state.server,
|
||||||
[false, Username, StateData#state.server,
|
[false, Username, StateData#state.server,
|
||||||
StateData#state.ip]),
|
StateData#state.ip]),
|
||||||
@ -1121,46 +1099,45 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
|
|||||||
R = NewStateData#state.resource,
|
R = NewStateData#state.resource,
|
||||||
JID = NewStateData#state.jid,
|
JID = NewStateData#state.jid,
|
||||||
case acl:match_rule(NewStateData#state.server,
|
case acl:match_rule(NewStateData#state.server,
|
||||||
NewStateData#state.access, JID) of
|
NewStateData#state.access, JID) of
|
||||||
allow ->
|
allow ->
|
||||||
?INFO_MSG("(~w) Opened session for ~s",
|
?INFO_MSG("(~w) Opened session for ~s",
|
||||||
[NewStateData#state.socket,
|
[NewStateData#state.socket, jlib:jid_to_string(JID)]),
|
||||||
jlib:jid_to_string(JID)]),
|
|
||||||
Res = jlib:make_result_iq_reply(El#xmlel{children = []}),
|
Res = jlib:make_result_iq_reply(El#xmlel{children = []}),
|
||||||
NewState = send_stanza(NewStateData, Res),
|
NewState = send_stanza(NewStateData, Res),
|
||||||
change_shaper(NewState, JID),
|
change_shaper(NewState, JID),
|
||||||
{Fs, Ts} = ejabberd_hooks:run_fold(
|
{Fs, Ts} = ejabberd_hooks:run_fold(
|
||||||
roster_get_subscription_lists,
|
roster_get_subscription_lists,
|
||||||
NewState#state.server,
|
NewState#state.server,
|
||||||
{[], []},
|
{[], []},
|
||||||
[U, NewState#state.server]),
|
[U, NewState#state.server]),
|
||||||
LJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
|
LJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
|
||||||
Fs1 = [LJID | Fs],
|
Fs1 = [LJID | Fs],
|
||||||
Ts1 = [LJID | Ts],
|
Ts1 = [LJID | Ts],
|
||||||
PrivList =
|
PrivList =
|
||||||
ejabberd_hooks:run_fold(
|
ejabberd_hooks:run_fold(
|
||||||
privacy_get_user_list, NewState#state.server,
|
privacy_get_user_list,
|
||||||
#userlist{},
|
NewState#state.server,
|
||||||
[U, NewState#state.server]),
|
#userlist{},
|
||||||
|
[U, NewState#state.server]),
|
||||||
Conn = get_conn_type(NewState),
|
Conn = get_conn_type(NewState),
|
||||||
Info = [{ip, NewState#state.ip}, {conn, Conn},
|
Info = [{ip, NewState#state.ip}, {conn, Conn},
|
||||||
{auth_module, NewState#state.auth_module}],
|
{auth_module, NewState#state.auth_module}],
|
||||||
ejabberd_sm:open_session(
|
ejabberd_sm:open_session(
|
||||||
NewState#state.sid, U, NewState#state.server, R, Info),
|
NewState#state.sid, U, NewState#state.server, R, Info),
|
||||||
UpdatedStateData =
|
UpdatedStateData =
|
||||||
NewState#state{
|
NewState#state{
|
||||||
conn = Conn,
|
conn = Conn,
|
||||||
pres_f = ?SETS:from_list(Fs1),
|
pres_f = ?SETS:from_list(Fs1),
|
||||||
pres_t = ?SETS:from_list(Ts1),
|
pres_t = ?SETS:from_list(Ts1),
|
||||||
privacy_list = PrivList},
|
privacy_list = PrivList},
|
||||||
fsm_next_state_pack(session_established,
|
fsm_next_state_pack(session_established,
|
||||||
UpdatedStateData);
|
UpdatedStateData);
|
||||||
_ ->
|
_ ->
|
||||||
ejabberd_hooks:run(forbidden_session_hook,
|
ejabberd_hooks:run(forbidden_session_hook,
|
||||||
NewStateData#state.server, [JID]),
|
NewStateData#state.server, [JID]),
|
||||||
?INFO_MSG("(~w) Forbidden session for ~s",
|
?INFO_MSG("(~w) Forbidden session for ~s",
|
||||||
[NewStateData#state.socket,
|
[NewStateData#state.socket, jlib:jid_to_string(JID)]),
|
||||||
jlib:jid_to_string(JID)]),
|
|
||||||
Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
|
Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
|
||||||
send_element(NewStateData, Err),
|
send_element(NewStateData, Err),
|
||||||
fsm_next_state(wait_for_session, NewStateData)
|
fsm_next_state(wait_for_session, NewStateData)
|
||||||
@ -1168,7 +1145,6 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
|
|||||||
_ ->
|
_ ->
|
||||||
fsm_next_state(wait_for_session, NewStateData)
|
fsm_next_state(wait_for_session, NewStateData)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
wait_for_session(timeout, StateData) ->
|
wait_for_session(timeout, StateData) ->
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_session({xmlstreamend, _Name}, StateData) ->
|
wait_for_session({xmlstreamend, _Name}, StateData) ->
|
||||||
@ -1230,8 +1206,7 @@ session_established(closed, #state{mgmt_state = active} = StateData) ->
|
|||||||
session_established(closed, StateData) ->
|
session_established(closed, StateData) ->
|
||||||
{stop, normal, StateData}.
|
{stop, normal, StateData}.
|
||||||
|
|
||||||
%% Process packets sent by user (coming from user on c2s XMPP
|
%% Process packets sent by user (coming from user on c2s XMPP connection)
|
||||||
%% connection)
|
|
||||||
session_established2(El, StateData) ->
|
session_established2(El, StateData) ->
|
||||||
#xmlel{name = Name, attrs = Attrs} = El,
|
#xmlel{name = Name, attrs = Attrs} = El,
|
||||||
NewStateData = update_num_stanzas_in(StateData, El),
|
NewStateData = update_num_stanzas_in(StateData, El),
|
||||||
@ -1323,37 +1298,9 @@ wait_for_resume(Event, StateData) ->
|
|||||||
?DEBUG("Ignoring event while waiting for resumption: ~p", [Event]),
|
?DEBUG("Ignoring event while waiting for resumption: ~p", [Event]),
|
||||||
fsm_next_state(wait_for_resume, StateData).
|
fsm_next_state(wait_for_resume, StateData).
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: StateName/3
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {reply, Reply, NextStateName, NextStateData} |
|
|
||||||
%% {reply, Reply, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData} |
|
|
||||||
%% {stop, Reason, Reply, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%state_name(Event, From, StateData) ->
|
|
||||||
% Reply = ok,
|
|
||||||
% {reply, Reply, state_name, StateData}.
|
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_event/3
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
handle_event(_Event, StateName, StateData) ->
|
handle_event(_Event, StateName, StateData) ->
|
||||||
fsm_next_state(StateName, StateData).
|
fsm_next_state(StateName, StateData).
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_sync_event/4
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {reply, Reply, NextStateName, NextStateData} |
|
|
||||||
%% {reply, Reply, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData} |
|
|
||||||
%% {stop, Reason, Reply, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
handle_sync_event({get_presence}, _From, StateName,
|
handle_sync_event({get_presence}, _From, StateName,
|
||||||
StateData) ->
|
StateData) ->
|
||||||
User = StateData#state.user,
|
User = StateData#state.user,
|
||||||
@ -1386,12 +1333,6 @@ handle_sync_event(_Event, _From, StateName,
|
|||||||
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
||||||
{ok, StateName, StateData}.
|
{ok, StateName, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_info/3
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
handle_info({send_text, Text}, StateName, StateData) ->
|
handle_info({send_text, Text}, StateName, StateData) ->
|
||||||
send_text(StateData, Text),
|
send_text(StateData, Text),
|
||||||
ejabberd_hooks:run(c2s_loop_debug, [Text]),
|
ejabberd_hooks:run(c2s_loop_debug, [Text]),
|
||||||
@ -1446,7 +1387,8 @@ handle_info({route, _From, _To, {broadcast, Data}},
|
|||||||
jlib:jid_remove_resource(StateData#state.jid),
|
jlib:jid_remove_resource(StateData#state.jid),
|
||||||
StateData#state.jid,
|
StateData#state.jid,
|
||||||
jlib:iq_to_xml(PrivPushIQ)),
|
jlib:iq_to_xml(PrivPushIQ)),
|
||||||
NewState = send_stanza(StateData, PrivPushEl),
|
NewState = send_stanza(
|
||||||
|
StateData, PrivPushEl),
|
||||||
fsm_next_state(StateName,
|
fsm_next_state(StateName,
|
||||||
NewState#state{privacy_list = NewPL})
|
NewState#state{privacy_list = NewPL})
|
||||||
end;
|
end;
|
||||||
@ -1682,7 +1624,8 @@ handle_info({route, From, To,
|
|||||||
From, To,
|
From, To,
|
||||||
Packet, in)
|
Packet, in)
|
||||||
of
|
of
|
||||||
allow -> {true, Attrs, StateData};
|
allow ->
|
||||||
|
{true, Attrs, StateData};
|
||||||
deny ->
|
deny ->
|
||||||
case xml:get_attr_s(<<"type">>, Attrs) of
|
case xml:get_attr_s(<<"type">>, Attrs) of
|
||||||
<<"error">> -> ok;
|
<<"error">> -> ok;
|
||||||
@ -1700,14 +1643,14 @@ handle_info({route, From, To,
|
|||||||
end,
|
end,
|
||||||
if Pass ->
|
if Pass ->
|
||||||
Attrs2 =
|
Attrs2 =
|
||||||
jlib:replace_from_to_attrs(jlib:jid_to_string(From),
|
jlib:replace_from_to_attrs(jlib:jid_to_string(From),
|
||||||
jlib:jid_to_string(To), NewAttrs),
|
jlib:jid_to_string(To), NewAttrs),
|
||||||
FixedPacket0 = #xmlel{name = Name, attrs = Attrs2, children = Els},
|
FixedPacket0 = #xmlel{name = Name, attrs = Attrs2, children = Els},
|
||||||
FixedPacket = ejabberd_hooks:run_fold(
|
FixedPacket = ejabberd_hooks:run_fold(
|
||||||
user_receive_packet,
|
user_receive_packet,
|
||||||
NewState#state.server,
|
NewState#state.server,
|
||||||
FixedPacket0,
|
FixedPacket0,
|
||||||
[NewState, NewState#state.jid, From, To]),
|
[NewState, NewState#state.jid, From, To]),
|
||||||
SentStateData = send_packet(NewState, FixedPacket),
|
SentStateData = send_packet(NewState, FixedPacket),
|
||||||
ejabberd_hooks:run(c2s_loop_debug, [{route, From, To, Packet}]),
|
ejabberd_hooks:run(c2s_loop_debug, [{route, From, To, Packet}]),
|
||||||
fsm_next_state(StateName, SentStateData);
|
fsm_next_state(StateName, SentStateData);
|
||||||
@ -1798,23 +1741,11 @@ handle_info(Info, StateName, StateData) ->
|
|||||||
?ERROR_MSG("Unexpected info: ~p", [Info]),
|
?ERROR_MSG("Unexpected info: ~p", [Info]),
|
||||||
fsm_next_state(StateName, StateData).
|
fsm_next_state(StateName, StateData).
|
||||||
|
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: print_state/1
|
|
||||||
%% Purpose: Prepare the state to be printed on error log
|
|
||||||
%% Returns: State to print
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
print_state(State = #state{pres_t = T, pres_f = F, pres_a = A}) ->
|
print_state(State = #state{pres_t = T, pres_f = F, pres_a = A}) ->
|
||||||
State#state{pres_t = {pres_t, ?SETS:size(T)},
|
State#state{pres_t = {pres_t, (?SETS):size(T)},
|
||||||
pres_f = {pres_f, ?SETS:size(F)},
|
pres_f = {pres_f, (?SETS):size(F)},
|
||||||
pres_a = {pres_a, ?SETS:size(A)}
|
pres_a = {pres_a, (?SETS):size(A)}}.
|
||||||
}.
|
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: terminate/3
|
|
||||||
%% Purpose: Shutdown the fsm
|
|
||||||
%% Returns: any
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
terminate(_Reason, StateName, StateData) ->
|
terminate(_Reason, StateName, StateData) ->
|
||||||
case StateData#state.mgmt_state of
|
case StateData#state.mgmt_state of
|
||||||
resumed ->
|
resumed ->
|
||||||
@ -1986,7 +1917,7 @@ is_auth_packet(El) ->
|
|||||||
#iq{id = ID, type = Type, xmlns = ?NS_AUTH, sub_el = SubEl} ->
|
#iq{id = ID, type = Type, xmlns = ?NS_AUTH, sub_el = SubEl} ->
|
||||||
#xmlel{children = Els} = SubEl,
|
#xmlel{children = Els} = SubEl,
|
||||||
{auth, ID, Type,
|
{auth, ID, Type,
|
||||||
get_auth_tags(Els, <<"">>, <<"">>, <<"">>, <<"">>)};
|
get_auth_tags(Els, <<"">>, <<"">>, <<"">>, <<"">>)};
|
||||||
_ -> false
|
_ -> false
|
||||||
end.
|
end.
|
||||||
|
|
||||||
@ -2042,12 +1973,11 @@ process_presence_probe(From, To, StateData) ->
|
|||||||
undefined ->
|
undefined ->
|
||||||
ok;
|
ok;
|
||||||
_ ->
|
_ ->
|
||||||
Cond = ?SETS:is_element(LFrom, StateData#state.pres_f)
|
Cond = ((?SETS):is_element(LFrom, StateData#state.pres_f)
|
||||||
orelse
|
orelse
|
||||||
((LFrom /= LBFrom) andalso
|
((LFrom /= LBFrom) andalso
|
||||||
?SETS:is_element(LBFrom, StateData#state.pres_f)),
|
(?SETS):is_element(LBFrom, StateData#state.pres_f))),
|
||||||
if
|
if Cond ->
|
||||||
Cond ->
|
|
||||||
%% To is the one sending the presence (the probe target)
|
%% To is the one sending the presence (the probe target)
|
||||||
Packet = jlib:add_delay_info(StateData#state.pres_last, To,
|
Packet = jlib:add_delay_info(StateData#state.pres_last, To,
|
||||||
StateData#state.pres_timestamp),
|
StateData#state.pres_timestamp),
|
||||||
@ -2283,11 +2213,11 @@ roster_change(IJID, ISubscription, StateData) ->
|
|||||||
OldIsFrom = (?SETS):is_element(LIJID, StateData#state.pres_f),
|
OldIsFrom = (?SETS):is_element(LIJID, StateData#state.pres_f),
|
||||||
FSet = if
|
FSet = if
|
||||||
IsFrom -> (?SETS):add_element(LIJID, StateData#state.pres_f);
|
IsFrom -> (?SETS):add_element(LIJID, StateData#state.pres_f);
|
||||||
not IsFrom -> remove_element(LIJID, StateData#state.pres_f)
|
true -> remove_element(LIJID, StateData#state.pres_f)
|
||||||
end,
|
end,
|
||||||
TSet = if
|
TSet = if
|
||||||
IsTo -> (?SETS):add_element(LIJID, StateData#state.pres_t);
|
IsTo -> (?SETS):add_element(LIJID, StateData#state.pres_t);
|
||||||
not IsTo -> remove_element(LIJID, StateData#state.pres_t)
|
true -> remove_element(LIJID, StateData#state.pres_t)
|
||||||
end,
|
end,
|
||||||
case StateData#state.pres_last of
|
case StateData#state.pres_last of
|
||||||
undefined ->
|
undefined ->
|
||||||
@ -2543,12 +2473,12 @@ check_from(El, FromJID) ->
|
|||||||
#jid{} ->
|
#jid{} ->
|
||||||
if
|
if
|
||||||
(JID#jid.luser == FromJID#jid.luser) and
|
(JID#jid.luser == FromJID#jid.luser) and
|
||||||
(JID#jid.lserver == FromJID#jid.lserver) and
|
(JID#jid.lserver == FromJID#jid.lserver) and
|
||||||
(JID#jid.lresource == FromJID#jid.lresource) ->
|
(JID#jid.lresource == FromJID#jid.lresource) ->
|
||||||
El;
|
El;
|
||||||
(JID#jid.luser == FromJID#jid.luser) and
|
(JID#jid.luser == FromJID#jid.luser) and
|
||||||
(JID#jid.lserver == FromJID#jid.lserver) and
|
(JID#jid.lserver == FromJID#jid.lserver) and
|
||||||
(JID#jid.lresource == <<"">>) ->
|
(JID#jid.lresource == <<"">>) ->
|
||||||
El;
|
El;
|
||||||
true ->
|
true ->
|
||||||
'invalid-from'
|
'invalid-from'
|
||||||
|
@ -75,13 +75,6 @@
|
|||||||
tref :: reference(),
|
tref :: reference(),
|
||||||
args :: any()}).
|
args :: any()}).
|
||||||
|
|
||||||
%%====================================================================
|
|
||||||
%% API
|
|
||||||
%%====================================================================
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
|
|
||||||
%% Description: Starts the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
start_link() ->
|
start_link() ->
|
||||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [],
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [],
|
||||||
[]).
|
[]).
|
||||||
@ -276,12 +269,6 @@ create_captcha_x(SID, To, Lang, Limiter, HeadEls,
|
|||||||
Err -> Err
|
Err -> Err
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @spec (Id::string(), Lang::string()) -> {FormEl, {ImgEl, TextEl, IdEl, KeyEl}} | captcha_not_found
|
|
||||||
%% where FormEl = xmlelement()
|
|
||||||
%% ImgEl = xmlelement()
|
|
||||||
%% TextEl = xmlelement()
|
|
||||||
%% IdEl = xmlelement()
|
|
||||||
%% KeyEl = xmlelement()
|
|
||||||
-spec build_captcha_html(binary(), binary()) -> captcha_not_found |
|
-spec build_captcha_html(binary(), binary()) -> captcha_not_found |
|
||||||
{xmlel(),
|
{xmlel(),
|
||||||
{xmlel(), xmlel(),
|
{xmlel(), xmlel(),
|
||||||
@ -330,12 +317,6 @@ build_captcha_html(Id, Lang) ->
|
|||||||
_ -> captcha_not_found
|
_ -> captcha_not_found
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @spec (Id::string(), ProvidedKey::string()) -> captcha_valid | captcha_non_valid | captcha_not_found
|
|
||||||
-spec check_captcha(binary(), binary()) -> captcha_not_found |
|
|
||||||
captcha_valid |
|
|
||||||
captcha_non_valid.
|
|
||||||
|
|
||||||
|
|
||||||
-spec process_reply(xmlel()) -> ok | {error, bad_match | not_found | malformed}.
|
-spec process_reply(xmlel()) -> ok | {error, bad_match | not_found | malformed}.
|
||||||
|
|
||||||
process_reply(#xmlel{} = El) ->
|
process_reply(#xmlel{} = El) ->
|
||||||
@ -405,9 +386,6 @@ process(_Handlers,
|
|||||||
process(_Handlers, _Request) ->
|
process(_Handlers, _Request) ->
|
||||||
ejabberd_web:error(not_found).
|
ejabberd_web:error(not_found).
|
||||||
|
|
||||||
%%====================================================================
|
|
||||||
%% gen_server callbacks
|
|
||||||
%%====================================================================
|
|
||||||
init([]) ->
|
init([]) ->
|
||||||
mnesia:delete_table(captcha),
|
mnesia:delete_table(captcha),
|
||||||
ets:new(captcha,
|
ets:new(captcha,
|
||||||
@ -454,16 +432,6 @@ terminate(_Reason, _State) -> ok.
|
|||||||
|
|
||||||
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%%% Internal functions
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: create_image() -> {ok, Type, Key, Image} | {error, Reason}
|
|
||||||
%% Type = "image/png" | "image/jpeg" | "image/gif"
|
|
||||||
%% Key = string()
|
|
||||||
%% Image = binary()
|
|
||||||
%% Reason = atom()
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
create_image() -> create_image(undefined).
|
create_image() -> create_image(undefined).
|
||||||
|
|
||||||
create_image(Limiter) ->
|
create_image(Limiter) ->
|
||||||
@ -596,12 +564,6 @@ is_limited(Limiter) ->
|
|||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: cmd(Cmd) -> Data | {error, Reason}
|
|
||||||
%% Cmd = string()
|
|
||||||
%% Data = binary()
|
|
||||||
%% Description: os:cmd/1 replacement
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
-define(CMD_TIMEOUT, 5000).
|
-define(CMD_TIMEOUT, 5000).
|
||||||
|
|
||||||
-define(MAX_FILE_SIZE, 64 * 1024).
|
-define(MAX_FILE_SIZE, 64 * 1024).
|
||||||
@ -663,6 +625,10 @@ lookup_captcha(Id) ->
|
|||||||
_ -> {error, enoent}
|
_ -> {error, enoent}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec check_captcha(binary(), binary()) -> captcha_not_found |
|
||||||
|
captcha_valid |
|
||||||
|
captcha_non_valid.
|
||||||
|
|
||||||
check_captcha(Id, ProvidedKey) ->
|
check_captcha(Id, ProvidedKey) ->
|
||||||
case ets:lookup(captcha, Id) of
|
case ets:lookup(captcha, Id) of
|
||||||
[#captcha{pid = Pid, args = Args, key = ValidKey,
|
[#captcha{pid = Pid, args = Args, key = ValidKey,
|
||||||
|
53
src/ejabberd_cluster.erl
Normal file
53
src/ejabberd_cluster.erl
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% File : ejabberd_cluster.erl
|
||||||
|
%%% Author : Christophe Romain <christophe.romain@process-one.net>
|
||||||
|
%%% Purpose : Ejabberd clustering management
|
||||||
|
%%% Created : 7 Oct 2015 by Christophe Romain <christophe.romain@process-one.net>
|
||||||
|
%%%
|
||||||
|
%%%
|
||||||
|
%%% ejabberd, Copyright (C) 2002-2015 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(ejabberd_cluster).
|
||||||
|
|
||||||
|
%% API
|
||||||
|
-export([get_nodes/0, call/4, multicall/3, multicall/4]).
|
||||||
|
|
||||||
|
-include("ejabberd.hrl").
|
||||||
|
-include("logger.hrl").
|
||||||
|
|
||||||
|
-spec get_nodes() -> [node()].
|
||||||
|
|
||||||
|
get_nodes() ->
|
||||||
|
mnesia:system_info(running_db_nodes).
|
||||||
|
|
||||||
|
-spec call(node(), module(), atom(), [any()]) -> any().
|
||||||
|
|
||||||
|
call(Node, Module, Function, Args) ->
|
||||||
|
rpc:call(Node, Module, Function, Args, 5000).
|
||||||
|
|
||||||
|
-spec multicall(module(), atom(), [any()]) -> {list(), [node()]}.
|
||||||
|
|
||||||
|
multicall(Module, Function, Args) ->
|
||||||
|
multicall(get_nodes(), Module, Function, Args).
|
||||||
|
|
||||||
|
-spec multicall([node()], module(), atom(), list()) -> {list(), [node()]}.
|
||||||
|
|
||||||
|
multicall(Nodes, Module, Function, Args) ->
|
||||||
|
rpc:multicall(Nodes, Module, Function, Args, 5000).
|
||||||
|
|
@ -326,7 +326,7 @@ execute_command(Name, Arguments) ->
|
|||||||
) -> any().
|
) -> any().
|
||||||
|
|
||||||
%% @spec (AccessCommands, Auth, Name::atom(), Arguments) -> ResultTerm | {error, Error}
|
%% @spec (AccessCommands, Auth, Name::atom(), Arguments) -> ResultTerm | {error, Error}
|
||||||
%% where
|
%% where
|
||||||
%% AccessCommands = [{Access, CommandNames, Arguments}]
|
%% AccessCommands = [{Access, CommandNames, Arguments}]
|
||||||
%% Auth = {User::string(), Server::string(), Password::string(), Admin::boolean()}
|
%% Auth = {User::string(), Server::string(), Password::string(), Admin::boolean()}
|
||||||
%% | noauth
|
%% | noauth
|
||||||
@ -414,7 +414,7 @@ get_tags_commands() ->
|
|||||||
%% -----------------------------
|
%% -----------------------------
|
||||||
|
|
||||||
%% @spec (AccessCommands, Auth, Method, Command, Arguments) -> ok
|
%% @spec (AccessCommands, Auth, Method, Command, Arguments) -> ok
|
||||||
%% where
|
%% where
|
||||||
%% AccessCommands = [ {Access, CommandNames, Arguments} ]
|
%% AccessCommands = [ {Access, CommandNames, Arguments} ]
|
||||||
%% Auth = {User::string(), Server::string(), Password::string()} | noauth
|
%% Auth = {User::string(), Server::string(), Password::string()} | noauth
|
||||||
%% Method = atom()
|
%% Method = atom()
|
||||||
@ -479,8 +479,8 @@ check_auth(Command, {User, Server, {oauth, Token}, _}) ->
|
|||||||
check_auth(_Command, {User, Server, Password, _}) when is_binary(Password) ->
|
check_auth(_Command, {User, Server, Password, _}) when is_binary(Password) ->
|
||||||
%% Check the account exists and password is valid
|
%% Check the account exists and password is valid
|
||||||
case ejabberd_auth:check_password(User, Server, Password) of
|
case ejabberd_auth:check_password(User, Server, Password) of
|
||||||
true -> {ok, User, Server};
|
true -> {ok, User, Server};
|
||||||
_ -> throw({error, invalid_account_data})
|
_ -> throw({error, invalid_account_data})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
check_access(Command, all, _)
|
check_access(Command, all, _)
|
||||||
@ -528,9 +528,9 @@ check_access_arguments(Command, ArgumentRestrictions, Arguments) ->
|
|||||||
|
|
||||||
tag_arguments(ArgsDefs, Args) ->
|
tag_arguments(ArgsDefs, Args) ->
|
||||||
lists:zipwith(
|
lists:zipwith(
|
||||||
fun({ArgName, _ArgType}, ArgValue) ->
|
fun({ArgName, _ArgType}, ArgValue) ->
|
||||||
{ArgName, ArgValue}
|
{ArgName, ArgValue}
|
||||||
end,
|
end,
|
||||||
ArgsDefs,
|
ArgsDefs,
|
||||||
Args).
|
Args).
|
||||||
|
|
||||||
|
@ -192,7 +192,6 @@ env_binary_to_list(Application, Parameter) ->
|
|||||||
%% Returns a list of plain terms,
|
%% Returns a list of plain terms,
|
||||||
%% in which the options 'include_config_file' were parsed
|
%% in which the options 'include_config_file' were parsed
|
||||||
%% and the terms in those files were included.
|
%% and the terms in those files were included.
|
||||||
%% @spec(string()) -> [term()]
|
|
||||||
%% @spec(iolist()) -> [term()]
|
%% @spec(iolist()) -> [term()]
|
||||||
get_plain_terms_file(File) ->
|
get_plain_terms_file(File) ->
|
||||||
get_plain_terms_file(File, [{include_files, true}]).
|
get_plain_terms_file(File, [{include_files, true}]).
|
||||||
@ -844,6 +843,7 @@ replace_module(mod_roster_odbc) -> {mod_roster, odbc};
|
|||||||
replace_module(mod_shared_roster_odbc) -> {mod_shared_roster, odbc};
|
replace_module(mod_shared_roster_odbc) -> {mod_shared_roster, odbc};
|
||||||
replace_module(mod_vcard_odbc) -> {mod_vcard, odbc};
|
replace_module(mod_vcard_odbc) -> {mod_vcard, odbc};
|
||||||
replace_module(mod_vcard_xupdate_odbc) -> {mod_vcard_xupdate, odbc};
|
replace_module(mod_vcard_xupdate_odbc) -> {mod_vcard_xupdate, odbc};
|
||||||
|
replace_module(mod_pubsub_odbc) -> {mod_pubsub, odbc};
|
||||||
replace_module(Module) ->
|
replace_module(Module) ->
|
||||||
case is_elixir_module(Module) of
|
case is_elixir_module(Module) of
|
||||||
true -> expand_elixir_module(Module);
|
true -> expand_elixir_module(Module);
|
||||||
|
@ -80,7 +80,7 @@ start() ->
|
|||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
Node = list_to_atom(SNode1),
|
Node = list_to_atom(SNode1),
|
||||||
Status = case rpc:call(Node, ?MODULE, process, [Args]) of
|
Status = case ejabberd_cluster:call(Node, ?MODULE, process, [Args]) of
|
||||||
{badrpc, Reason} ->
|
{badrpc, Reason} ->
|
||||||
print("Failed RPC connection to the node ~p: ~p~n",
|
print("Failed RPC connection to the node ~p: ~p~n",
|
||||||
[Node, Reason]),
|
[Node, Reason]),
|
||||||
@ -392,7 +392,10 @@ format_result(ElementsTuple, {_Name, {tuple, ElementsDef}}) ->
|
|||||||
fun({Element, ElementDef}) ->
|
fun({Element, ElementDef}) ->
|
||||||
["\t" | format_result(Element, ElementDef)]
|
["\t" | format_result(Element, ElementDef)]
|
||||||
end,
|
end,
|
||||||
ElementsAndDef)].
|
ElementsAndDef)];
|
||||||
|
|
||||||
|
format_result(404, {_Name, _}) ->
|
||||||
|
make_status(not_found).
|
||||||
|
|
||||||
make_status(ok) -> ?STATUS_SUCCESS;
|
make_status(ok) -> ?STATUS_SUCCESS;
|
||||||
make_status(true) -> ?STATUS_SUCCESS;
|
make_status(true) -> ?STATUS_SUCCESS;
|
||||||
|
@ -58,10 +58,6 @@
|
|||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% API
|
%% API
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
|
|
||||||
%% Description: Starts the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
start_link(Module, SockMod, Socket, Opts, Receiver) ->
|
start_link(Module, SockMod, Socket, Opts, Receiver) ->
|
||||||
gen_server:start_link(?MODULE,
|
gen_server:start_link(?MODULE,
|
||||||
[Module, SockMod, Socket, Opts, Receiver], []).
|
[Module, SockMod, Socket, Opts, Receiver], []).
|
||||||
@ -137,18 +133,10 @@ peername(_FsmRef) ->
|
|||||||
%%gen_server:call(FsmRef, peername).
|
%%gen_server:call(FsmRef, peername).
|
||||||
{ok, {{0, 0, 0, 0}, 0}}.
|
{ok, {{0, 0, 0, 0}, 0}}.
|
||||||
|
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: init(Args) -> {ok, State} |
|
|
||||||
%% {ok, State, Timeout} |
|
|
||||||
%% ignore |
|
|
||||||
%% {stop, Reason}
|
|
||||||
%% Description: Initiates the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
init([Module, SockMod, Socket, Opts, Receiver]) ->
|
init([Module, SockMod, Socket, Opts, Receiver]) ->
|
||||||
Node = ejabberd_node_groups:get_closest_node(backend),
|
Node = ejabberd_node_groups:get_closest_node(backend),
|
||||||
{SockMod2, Socket2} = check_starttls(SockMod, Socket, Receiver, Opts),
|
{SockMod2, Socket2} = check_starttls(SockMod, Socket, Receiver, Opts),
|
||||||
@ -159,15 +147,6 @@ init([Module, SockMod, Socket, Opts, Receiver]) ->
|
|||||||
socket = Socket2,
|
socket = Socket2,
|
||||||
receiver = Receiver}}.
|
receiver = Receiver}}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
|
|
||||||
%% {reply, Reply, State, Timeout} |
|
|
||||||
%% {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, Reply, State} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling call messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_call({starttls, TLSOpts}, _From, State) ->
|
handle_call({starttls, TLSOpts}, _From, State) ->
|
||||||
{ok, TLSSocket} = p1_tls:tcp_to_tls(State#state.socket, TLSOpts),
|
{ok, TLSSocket} = p1_tls:tcp_to_tls(State#state.socket, TLSOpts),
|
||||||
ejabberd_receiver:starttls(State#state.receiver, TLSSocket),
|
ejabberd_receiver:starttls(State#state.receiver, TLSSocket),
|
||||||
@ -184,7 +163,6 @@ handle_call({starttls, TLSOpts, Data}, _From, State) ->
|
|||||||
{reply, Reply,
|
{reply, Reply,
|
||||||
State#state{socket = TLSSocket, sockmod = p1_tls},
|
State#state{socket = TLSSocket, sockmod = p1_tls},
|
||||||
?HIBERNATE_TIMEOUT};
|
?HIBERNATE_TIMEOUT};
|
||||||
|
|
||||||
handle_call({compress, Data}, _From, State) ->
|
handle_call({compress, Data}, _From, State) ->
|
||||||
{ok, ZlibSocket} =
|
{ok, ZlibSocket} =
|
||||||
ejabberd_receiver:compress(State#state.receiver, Data),
|
ejabberd_receiver:compress(State#state.receiver, Data),
|
||||||
@ -238,21 +216,9 @@ handle_call(peername, _From, State) ->
|
|||||||
handle_call(_Request, _From, State) ->
|
handle_call(_Request, _From, State) ->
|
||||||
Reply = ok, {reply, Reply, State, ?HIBERNATE_TIMEOUT}.
|
Reply = ok, {reply, Reply, State, ?HIBERNATE_TIMEOUT}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_cast(Msg, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_cast(_Msg, State) ->
|
handle_cast(_Msg, State) ->
|
||||||
{noreply, State, ?HIBERNATE_TIMEOUT}.
|
{noreply, State, ?HIBERNATE_TIMEOUT}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_info(Info, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling all non call/cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_info(timeout, State) ->
|
handle_info(timeout, State) ->
|
||||||
proc_lib:hibernate(gen_server, enter_loop,
|
proc_lib:hibernate(gen_server, enter_loop,
|
||||||
[?MODULE, [], State]),
|
[?MODULE, [], State]),
|
||||||
@ -260,31 +226,16 @@ handle_info(timeout, State) ->
|
|||||||
handle_info(_Info, State) ->
|
handle_info(_Info, State) ->
|
||||||
{noreply, State, ?HIBERNATE_TIMEOUT}.
|
{noreply, State, ?HIBERNATE_TIMEOUT}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: terminate(Reason, State) -> void()
|
|
||||||
%% Description: This function is called by a gen_server when it is about to
|
|
||||||
%% terminate. It should be the opposite of Module:init/1 and do any necessary
|
|
||||||
%% cleaning up. When it returns, the gen_server terminates with Reason.
|
|
||||||
%% The return value is ignored.
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
terminate(_Reason, _State) -> ok.
|
terminate(_Reason, _State) -> ok.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
|
|
||||||
%% Description: Convert process state when code is changed
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%%% Internal functions
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
check_starttls(SockMod, Socket, Receiver, Opts) ->
|
check_starttls(SockMod, Socket, Receiver, Opts) ->
|
||||||
TLSEnabled = proplists:get_bool(tls, Opts),
|
TLSEnabled = proplists:get_bool(tls, Opts),
|
||||||
TLSOpts = lists:filter(fun({certfile, _}) -> true;
|
TLSOpts = lists:filter(fun({certfile, _}) -> true;
|
||||||
(_) -> false
|
(_) -> false
|
||||||
end, Opts),
|
end, Opts),
|
||||||
if
|
if TLSEnabled ->
|
||||||
TLSEnabled ->
|
|
||||||
{ok, TLSSocket} = p1_tls:tcp_to_tls(Socket, TLSOpts),
|
{ok, TLSSocket} = p1_tls:tcp_to_tls(Socket, TLSOpts),
|
||||||
ejabberd_receiver:starttls(Receiver, TLSSocket),
|
ejabberd_receiver:starttls(Receiver, TLSSocket),
|
||||||
{p1_tls, TLSSocket};
|
{p1_tls, TLSSocket};
|
||||||
|
@ -58,9 +58,6 @@
|
|||||||
|
|
||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
|
|
||||||
%% Timeout of 5 seconds in calls to distributed hooks
|
|
||||||
-define(TIMEOUT_DISTRIBUTED_HOOK, 5000).
|
|
||||||
|
|
||||||
-record(state, {}).
|
-record(state, {}).
|
||||||
-type local_hook() :: { Seq :: integer(), Module :: atom(), Function :: atom()}.
|
-type local_hook() :: { Seq :: integer(), Module :: atom(), Function :: atom()}.
|
||||||
-type distributed_hook() :: { Seq :: integer(), Node :: atom(), Module :: atom(), Function :: atom()}.
|
-type distributed_hook() :: { Seq :: integer(), Node :: atom(), Module :: atom(), Function :: atom()}.
|
||||||
@ -310,7 +307,7 @@ run1([], _Hook, _Args) ->
|
|||||||
%% It is not attempted again in case of failure. Next hook will be executed
|
%% It is not attempted again in case of failure. Next hook will be executed
|
||||||
run1([{_Seq, Node, Module, Function} | Ls], Hook, Args) ->
|
run1([{_Seq, Node, Module, Function} | Ls], Hook, Args) ->
|
||||||
%% MR: Should we have a safe rpc, like we have a safe apply or is bad_rpc enough ?
|
%% MR: Should we have a safe rpc, like we have a safe apply or is bad_rpc enough ?
|
||||||
case rpc:call(Node, Module, Function, Args, ?TIMEOUT_DISTRIBUTED_HOOK) of
|
case ejabberd_cluster:call(Node, Module, Function, Args) of
|
||||||
timeout ->
|
timeout ->
|
||||||
?ERROR_MSG("Timeout on RPC to ~p~nrunning hook: ~p",
|
?ERROR_MSG("Timeout on RPC to ~p~nrunning hook: ~p",
|
||||||
[Node, {Hook, Args}]),
|
[Node, {Hook, Args}]),
|
||||||
@ -344,7 +341,7 @@ run1([{_Seq, Module, Function} | Ls], Hook, Args) ->
|
|||||||
run_fold1([], _Hook, Val, _Args) ->
|
run_fold1([], _Hook, Val, _Args) ->
|
||||||
Val;
|
Val;
|
||||||
run_fold1([{_Seq, Node, Module, Function} | Ls], Hook, Val, Args) ->
|
run_fold1([{_Seq, Node, Module, Function} | Ls], Hook, Val, Args) ->
|
||||||
case rpc:call(Node, Module, Function, [Val | Args], ?TIMEOUT_DISTRIBUTED_HOOK) of
|
case ejabberd_cluster:call(Node, Module, Function, [Val | Args]) of
|
||||||
{badrpc, Reason} ->
|
{badrpc, Reason} ->
|
||||||
?ERROR_MSG("Bad RPC error to ~p: ~p~nrunning hook: ~p",
|
?ERROR_MSG("Bad RPC error to ~p: ~p~nrunning hook: ~p",
|
||||||
[Node, Reason, {Hook, Args}]),
|
[Node, Reason, {Hook, Args}]),
|
||||||
|
@ -166,7 +166,8 @@ init({SockMod, Socket}, Opts) ->
|
|||||||
{error, _} -> State
|
{error, _} -> State
|
||||||
end.
|
end.
|
||||||
|
|
||||||
become_controller(_Pid) -> ok.
|
become_controller(_Pid) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
socket_type() ->
|
socket_type() ->
|
||||||
raw.
|
raw.
|
||||||
@ -201,22 +202,20 @@ parse_headers(#state{request_method = Method,
|
|||||||
trail = Data} =
|
trail = Data} =
|
||||||
State) ->
|
State) ->
|
||||||
PktType = case Method of
|
PktType = case Method of
|
||||||
undefined -> http_bin;
|
undefined -> http_bin;
|
||||||
_ -> httph_bin
|
_ -> httph_bin
|
||||||
end,
|
end,
|
||||||
case erlang:decode_packet(PktType, Data, []) of
|
case erlang:decode_packet(PktType, Data, []) of
|
||||||
{ok, Pkt, Rest} ->
|
{ok, Pkt, Rest} ->
|
||||||
NewState = process_header(State#state{trail = Rest}, {ok, Pkt}),
|
NewState = process_header(State#state{trail = Rest}, {ok, Pkt}),
|
||||||
case NewState#state.end_of_request of
|
case NewState#state.end_of_request of
|
||||||
true ->
|
true -> ok;
|
||||||
ok;
|
_ -> parse_headers(NewState)
|
||||||
_ ->
|
|
||||||
parse_headers(NewState)
|
|
||||||
end;
|
end;
|
||||||
{more, _} ->
|
{more, _} ->
|
||||||
receive_headers(State#state{trail = Data});
|
receive_headers(State#state{trail = Data});
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
process_header(State, Data) ->
|
process_header(State, Data) ->
|
||||||
@ -266,10 +265,8 @@ process_header(State, Data) ->
|
|||||||
State#state{request_host = Host,
|
State#state{request_host = Host,
|
||||||
request_headers = add_header(Name, Host, State)};
|
request_headers = add_header(Name, Host, State)};
|
||||||
{ok, {http_header, _, Name, _, Value}} when is_binary(Name) ->
|
{ok, {http_header, _, Name, _, Value}} when is_binary(Name) ->
|
||||||
State#state{request_headers =
|
State#state{request_headers =
|
||||||
add_header(normalize_header_name(Name),
|
add_header(normalize_header_name(Name), Value, State)};
|
||||||
Value,
|
|
||||||
State)};
|
|
||||||
{ok, {http_header, _, Name, _, Value}} ->
|
{ok, {http_header, _, Name, _, Value}} ->
|
||||||
State#state{request_headers =
|
State#state{request_headers =
|
||||||
add_header(Name, Value, State)};
|
add_header(Name, Value, State)};
|
||||||
@ -322,14 +319,6 @@ get_host_really_served(Default, Provided) ->
|
|||||||
false -> Default
|
false -> Default
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @spec (SockMod, HostPort) -> {Host::string(), Port::integer(), TP}
|
|
||||||
%% where
|
|
||||||
%% SockMod = gen_tcp | tls
|
|
||||||
%% HostPort = string()
|
|
||||||
%% TP = http | https
|
|
||||||
%% @doc Given a socket and hostport header, return data of transfer protocol.
|
|
||||||
%% Note that HostPort can be a string of a host like "example.org",
|
|
||||||
%% or a string of a host and port like "example.org:5280".
|
|
||||||
get_transfer_protocol(SockMod, HostPort) ->
|
get_transfer_protocol(SockMod, HostPort) ->
|
||||||
[Host | PortList] = str:tokens(HostPort, <<":">>),
|
[Host | PortList] = str:tokens(HostPort, <<":">>),
|
||||||
case {SockMod, PortList} of
|
case {SockMod, PortList} of
|
||||||
@ -416,17 +405,17 @@ extract_path_query(_State) ->
|
|||||||
false.
|
false.
|
||||||
|
|
||||||
process_request(#state{request_method = Method,
|
process_request(#state{request_method = Method,
|
||||||
request_auth = Auth,
|
request_auth = Auth,
|
||||||
request_lang = Lang,
|
request_lang = Lang,
|
||||||
sockmod = SockMod,
|
sockmod = SockMod,
|
||||||
socket = Socket,
|
socket = Socket,
|
||||||
options = Options,
|
options = Options,
|
||||||
request_host = Host,
|
request_host = Host,
|
||||||
request_port = Port,
|
request_port = Port,
|
||||||
request_tp = TP,
|
request_tp = TP,
|
||||||
request_headers = RequestHeaders,
|
request_headers = RequestHeaders,
|
||||||
request_handlers = RequestHandlers,
|
request_handlers = RequestHandlers,
|
||||||
trail = Trail} = State) ->
|
trail = Trail} = State) ->
|
||||||
case extract_path_query(State) of
|
case extract_path_query(State) of
|
||||||
false ->
|
false ->
|
||||||
make_bad_request(State);
|
make_bad_request(State);
|
||||||
@ -476,7 +465,6 @@ process_request(#state{request_method = Method,
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
make_bad_request(State) ->
|
make_bad_request(State) ->
|
||||||
%% Support for X-Forwarded-From
|
|
||||||
make_xhtml_output(State, 400, [],
|
make_xhtml_output(State, 400, [],
|
||||||
ejabberd_web:make_xhtml([#xmlel{name = <<"h1">>,
|
ejabberd_web:make_xhtml([#xmlel{name = <<"h1">>,
|
||||||
attrs = [],
|
attrs = [],
|
||||||
@ -532,13 +520,13 @@ recv_data(State, Len, Acc) ->
|
|||||||
|
|
||||||
make_xhtml_output(State, Status, Headers, XHTML) ->
|
make_xhtml_output(State, Status, Headers, XHTML) ->
|
||||||
Data = case lists:member(html, Headers) of
|
Data = case lists:member(html, Headers) of
|
||||||
true ->
|
true ->
|
||||||
iolist_to_binary([?HTML_DOCTYPE,
|
iolist_to_binary([?HTML_DOCTYPE,
|
||||||
xml:element_to_binary(XHTML)]);
|
xml:element_to_binary(XHTML)]);
|
||||||
_ ->
|
_ ->
|
||||||
iolist_to_binary([?XHTML_DOCTYPE,
|
iolist_to_binary([?XHTML_DOCTYPE,
|
||||||
xml:element_to_binary(XHTML)])
|
xml:element_to_binary(XHTML)])
|
||||||
end,
|
end,
|
||||||
Headers1 = case lists:keysearch(<<"Content-Type">>, 1,
|
Headers1 = case lists:keysearch(<<"Content-Type">>, 1,
|
||||||
Headers)
|
Headers)
|
||||||
of
|
of
|
||||||
|
@ -1,11 +1,27 @@
|
|||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% File : ejabberd_http_bind.erl
|
%%% File : ejabberd_http_bind.erl
|
||||||
%%% Author : Stefan Strigler <steve@zeank.in-berlin.de>
|
%%% Author : Stefan Strigler <steve@zeank.in-berlin.de>
|
||||||
%%% Purpose : Implements XMPP over BOSH (XEP-0206) (formerly known as
|
%%% Purpose : Implements XMPP over BOSH (XEP-0206)
|
||||||
%%% HTTP Binding)
|
|
||||||
%%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de>
|
%%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de>
|
||||||
%%% Modified: may 2009 by Mickael Remond, Alexey Schepin
|
%%% Modified: may 2009 by Mickael Remond, Alexey Schepin
|
||||||
%%% Id : $Id: ejabberd_http_bind.erl 953 2009-05-07 10:40:40Z alexey $
|
%%%
|
||||||
|
%%%
|
||||||
|
%%% ejabberd, Copyright (C) 2002-2015 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(ejabberd_http_bind).
|
-module(ejabberd_http_bind).
|
||||||
@ -78,7 +94,7 @@
|
|||||||
wait_timer,
|
wait_timer,
|
||||||
ctime = 0,
|
ctime = 0,
|
||||||
timer,
|
timer,
|
||||||
pause=0,
|
pause = 0,
|
||||||
unprocessed_req_list = [], % list of request that have been delayed for proper reordering: {Request, PID}
|
unprocessed_req_list = [], % list of request that have been delayed for proper reordering: {Request, PID}
|
||||||
req_list = [], % list of requests (cache)
|
req_list = [], % list of requests (cache)
|
||||||
max_inactivity,
|
max_inactivity,
|
||||||
@ -132,19 +148,15 @@
|
|||||||
|
|
||||||
-define(PROCESS_DELAY_MAX, 1000).
|
-define(PROCESS_DELAY_MAX, 1000).
|
||||||
|
|
||||||
%% Line copied from mod_http_bind.erl
|
|
||||||
-define(PROCNAME_MHB, ejabberd_mod_http_bind).
|
-define(PROCNAME_MHB, ejabberd_mod_http_bind).
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%% API
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%% TODO: If compile with no supervisor option, start the session without
|
|
||||||
%% supervisor
|
|
||||||
start(XMPPDomain, Sid, Key, IP, HOpts) ->
|
start(XMPPDomain, Sid, Key, IP, HOpts) ->
|
||||||
?DEBUG("Starting session", []),
|
?DEBUG("Starting session", []),
|
||||||
SupervisorProc = gen_mod:get_module_proc(XMPPDomain, ?PROCNAME_MHB),
|
SupervisorProc = gen_mod:get_module_proc(XMPPDomain, ?PROCNAME_MHB),
|
||||||
case catch supervisor:start_child(SupervisorProc, [Sid, Key, IP, HOpts]) of
|
case catch supervisor:start_child(SupervisorProc,
|
||||||
{ok, Pid} -> {ok, Pid};
|
[Sid, Key, IP, HOpts])
|
||||||
|
of
|
||||||
|
{ok, Pid} -> {ok, Pid};
|
||||||
_ -> check_bind_module(XMPPDomain),
|
_ -> check_bind_module(XMPPDomain),
|
||||||
{error, "Cannot start HTTP bind session"}
|
{error, "Cannot start HTTP bind session"}
|
||||||
end.
|
end.
|
||||||
@ -222,7 +234,7 @@ process_request(Data, IP, HOpts) ->
|
|||||||
XmppDomain ->
|
XmppDomain ->
|
||||||
NXmppDomain = jlib:nameprep(XmppDomain),
|
NXmppDomain = jlib:nameprep(XmppDomain),
|
||||||
Sid = p1_sha:sha(term_to_binary({now(), make_ref()})),
|
Sid = p1_sha:sha(term_to_binary({now(), make_ref()})),
|
||||||
case start(NXmppDomain, Sid, <<"">>, IP, HOpts) of
|
case start(NXmppDomain, Sid, <<"">>, IP, HOpts) of
|
||||||
{error, _} ->
|
{error, _} ->
|
||||||
{500, ?HEADER,
|
{500, ?HEADER,
|
||||||
<<"<body type='terminate' condition='internal-se"
|
<<"<body type='terminate' condition='internal-se"
|
||||||
@ -323,13 +335,6 @@ handle_session_start(Pid, XmppDomain, Sid, Rid, Attrs,
|
|||||||
%%% Callback functions from gen_fsm
|
%%% Callback functions from gen_fsm
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: init/1
|
|
||||||
%% Returns: {ok, StateName, StateData} |
|
|
||||||
%% {ok, StateName, StateData, Timeout} |
|
|
||||||
%% ignore |
|
|
||||||
%% {stop, StopReason}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
init([Sid, Key, IP, HOpts]) ->
|
init([Sid, Key, IP, HOpts]) ->
|
||||||
?DEBUG("started: ~p", [{Sid, Key, IP}]),
|
?DEBUG("started: ~p", [{Sid, Key, IP}]),
|
||||||
Opts1 = ejabberd_c2s_config:get_c2s_limits(),
|
Opts1 = ejabberd_c2s_config:get_c2s_limits(),
|
||||||
@ -355,12 +360,6 @@ init([Sid, Key, IP, HOpts]) ->
|
|||||||
max_pause = ?MAX_PAUSE,
|
max_pause = ?MAX_PAUSE,
|
||||||
timer = Timer}}.
|
timer = Timer}}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_event/3
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
handle_event({become_controller, C2SPid}, StateName, StateData) ->
|
handle_event({become_controller, C2SPid}, StateName, StateData) ->
|
||||||
case StateData#state.input of
|
case StateData#state.input of
|
||||||
cancel ->
|
cancel ->
|
||||||
@ -381,15 +380,6 @@ handle_event({change_shaper, Shaper}, StateName,
|
|||||||
handle_event(_Event, StateName, StateData) ->
|
handle_event(_Event, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData}.
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_sync_event/4
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {reply, Reply, NextStateName, NextStateData} |
|
|
||||||
%% {reply, Reply, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData} |
|
|
||||||
%% {stop, Reason, Reply, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
handle_sync_event({send_xml, Packet}, _From, StateName,
|
handle_sync_event({send_xml, Packet}, _From, StateName,
|
||||||
#state{http_receiver = undefined} = StateData) ->
|
#state{http_receiver = undefined} = StateData) ->
|
||||||
Output = [Packet | StateData#state.output],
|
Output = [Packet | StateData#state.output],
|
||||||
@ -458,10 +448,8 @@ handle_sync_event(#http_put{payload_size =
|
|||||||
shaper_timer = NewShaperTimer});
|
shaper_timer = NewShaperTimer});
|
||||||
%% HTTP GET: send packets to the client
|
%% HTTP GET: send packets to the client
|
||||||
handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) ->
|
handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) ->
|
||||||
%% setup timer
|
|
||||||
TNow = tnow(),
|
TNow = tnow(),
|
||||||
if
|
if (Hold > 0) and
|
||||||
(Hold > 0) and
|
|
||||||
((StateData#state.output == []) or (StateData#state.rid < Rid)) and
|
((StateData#state.output == []) or (StateData#state.rid < Rid)) and
|
||||||
((TNow - StateData#state.ctime) < (Wait*1000*1000)) and
|
((TNow - StateData#state.ctime) < (Wait*1000*1000)) and
|
||||||
(StateData#state.rid =< Rid) and
|
(StateData#state.rid =< Rid) and
|
||||||
@ -469,7 +457,6 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) ->
|
|||||||
send_receiver_reply(StateData#state.http_receiver, {ok, empty}),
|
send_receiver_reply(StateData#state.http_receiver, {ok, empty}),
|
||||||
cancel_timer(StateData#state.wait_timer),
|
cancel_timer(StateData#state.wait_timer),
|
||||||
WaitTimer = erlang:start_timer(Wait * 1000, self(), []),
|
WaitTimer = erlang:start_timer(Wait * 1000, self(), []),
|
||||||
%% MR: Not sure we should cancel the state timer here.
|
|
||||||
cancel_timer(StateData#state.timer),
|
cancel_timer(StateData#state.timer),
|
||||||
{next_state, StateName, StateData#state{
|
{next_state, StateName, StateData#state{
|
||||||
http_receiver = From,
|
http_receiver = From,
|
||||||
@ -479,34 +466,30 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) ->
|
|||||||
true ->
|
true ->
|
||||||
cancel_timer(StateData#state.timer),
|
cancel_timer(StateData#state.timer),
|
||||||
Reply = {ok, StateData#state.output},
|
Reply = {ok, StateData#state.output},
|
||||||
%% save request
|
|
||||||
ReqList = [#hbr{rid = Rid,
|
ReqList = [#hbr{rid = Rid,
|
||||||
key = StateData#state.key,
|
key = StateData#state.key,
|
||||||
out = StateData#state.output
|
out = StateData#state.output}
|
||||||
} |
|
| [El
|
||||||
[El || El <- StateData#state.req_list,
|
|| El <- StateData#state.req_list,
|
||||||
El#hbr.rid /= Rid ]
|
El#hbr.rid /= Rid]],
|
||||||
],
|
if (StateData#state.http_receiver /= undefined) and
|
||||||
if
|
StateData#state.out_of_order_receiver ->
|
||||||
(StateData#state.http_receiver /= undefined) and
|
{reply, Reply, StateName,
|
||||||
StateData#state.out_of_order_receiver ->
|
StateData#state{output = [], timer = undefined,
|
||||||
{reply, Reply, StateName, StateData#state{
|
req_list = ReqList,
|
||||||
output = [],
|
out_of_order_receiver = false}};
|
||||||
timer = undefined,
|
true ->
|
||||||
req_list = ReqList,
|
send_receiver_reply(StateData#state.http_receiver, {ok, empty}),
|
||||||
out_of_order_receiver = false}};
|
cancel_timer(StateData#state.wait_timer),
|
||||||
true ->
|
Timer = set_inactivity_timer(StateData#state.pause,
|
||||||
send_receiver_reply(StateData#state.http_receiver, {ok, empty}),
|
StateData#state.max_inactivity),
|
||||||
cancel_timer(StateData#state.wait_timer),
|
{reply, Reply, StateName,
|
||||||
Timer = set_inactivity_timer(StateData#state.pause,
|
StateData#state{output = [],
|
||||||
StateData#state.max_inactivity),
|
http_receiver = undefined,
|
||||||
{reply, Reply, StateName,
|
wait_timer = undefined,
|
||||||
StateData#state{output = [],
|
timer = Timer,
|
||||||
http_receiver = undefined,
|
req_list = ReqList}}
|
||||||
wait_timer = undefined,
|
end
|
||||||
timer = Timer,
|
|
||||||
req_list = ReqList}}
|
|
||||||
end
|
|
||||||
end;
|
end;
|
||||||
handle_sync_event(peername, _From, StateName,
|
handle_sync_event(peername, _From, StateName,
|
||||||
StateData) ->
|
StateData) ->
|
||||||
@ -519,13 +502,6 @@ handle_sync_event(_Event, _From, StateName,
|
|||||||
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
||||||
{ok, StateName, StateData}.
|
{ok, StateName, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_info/3
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% We reached the max_inactivity timeout:
|
|
||||||
handle_info({timeout, Timer, _}, _StateName,
|
handle_info({timeout, Timer, _}, _StateName,
|
||||||
#state{id = SID, timer = Timer} = StateData) ->
|
#state{id = SID, timer = Timer} = StateData) ->
|
||||||
?INFO_MSG("Session timeout. Closing the HTTP bind "
|
?INFO_MSG("Session timeout. Closing the HTTP bind "
|
||||||
@ -558,11 +534,6 @@ handle_info({timeout, ShaperTimer, _}, StateName,
|
|||||||
handle_info(_, StateName, StateData) ->
|
handle_info(_, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData}.
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: terminate/3
|
|
||||||
%% Purpose: Shutdown the fsm
|
|
||||||
%% Returns: any
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
terminate(_Reason, _StateName, StateData) ->
|
terminate(_Reason, _StateName, StateData) ->
|
||||||
?DEBUG("terminate: Deleting session ~s",
|
?DEBUG("terminate: Deleting session ~s",
|
||||||
[StateData#state.id]),
|
[StateData#state.id]),
|
||||||
@ -804,19 +775,22 @@ http_put(Sid, Rid, Attrs, Payload, PayloadSize,
|
|||||||
?DEBUG("Looking for session: ~p", [Sid]),
|
?DEBUG("Looking for session: ~p", [Sid]),
|
||||||
case mnesia:dirty_read({http_bind, Sid}) of
|
case mnesia:dirty_read({http_bind, Sid}) of
|
||||||
[] ->
|
[] ->
|
||||||
{error, not_exists};
|
{error, not_exists};
|
||||||
[#http_bind{pid = FsmRef, hold=Hold, to={To, StreamVersion}}=Sess] ->
|
[#http_bind{pid = FsmRef, hold=Hold,
|
||||||
NewStream =
|
to= {To, StreamVersion}} = Sess] ->
|
||||||
case StreamStart of
|
NewStream = case StreamStart of
|
||||||
true ->
|
true -> {To, StreamVersion};
|
||||||
{To, StreamVersion};
|
_ -> <<"">>
|
||||||
_ ->
|
end,
|
||||||
<<"">>
|
{gen_fsm:sync_send_all_state_event(
|
||||||
end,
|
FsmRef, #http_put{rid = Rid,
|
||||||
{gen_fsm:sync_send_all_state_event(
|
attrs = Attrs,
|
||||||
FsmRef, #http_put{rid = Rid, attrs = Attrs, payload = Payload,
|
payload = Payload,
|
||||||
payload_size = PayloadSize, hold = Hold,
|
payload_size = PayloadSize,
|
||||||
stream = NewStream, ip = IP}, 30000), Sess}
|
hold = Hold,
|
||||||
|
stream = NewStream,
|
||||||
|
ip = IP},
|
||||||
|
30000), Sess}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
handle_http_put_error(Reason,
|
handle_http_put_error(Reason,
|
||||||
@ -1189,7 +1163,6 @@ set_inactivity_timer(Pause, _MaxInactivity)
|
|||||||
set_inactivity_timer(_Pause, MaxInactivity) ->
|
set_inactivity_timer(_Pause, MaxInactivity) ->
|
||||||
erlang:start_timer(MaxInactivity, self(), []).
|
erlang:start_timer(MaxInactivity, self(), []).
|
||||||
|
|
||||||
%% TODO: Use tail recursion and list reverse ?
|
|
||||||
elements_to_string([]) -> [];
|
elements_to_string([]) -> [];
|
||||||
elements_to_string([El | Els]) ->
|
elements_to_string([El | Els]) ->
|
||||||
[xml:element_to_binary(El) | elements_to_string(Els)].
|
[xml:element_to_binary(El) | elements_to_string(Els)].
|
||||||
|
@ -175,13 +175,6 @@ bounce_resource_packet(From, To, Packet) ->
|
|||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: init(Args) -> {ok, State} |
|
|
||||||
%% {ok, State, Timeout} |
|
|
||||||
%% ignore |
|
|
||||||
%% {stop, Reason}
|
|
||||||
%% Description: Initiates the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
init([]) ->
|
init([]) ->
|
||||||
lists:foreach(fun (Host) ->
|
lists:foreach(fun (Host) ->
|
||||||
ejabberd_router:register_route(Host,
|
ejabberd_router:register_route(Host,
|
||||||
@ -200,28 +193,7 @@ init([]) ->
|
|||||||
mnesia:add_table_copy(iq_response, node(), ram_copies),
|
mnesia:add_table_copy(iq_response, node(), ram_copies),
|
||||||
{ok, #state{}}.
|
{ok, #state{}}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
|
|
||||||
%% {reply, Reply, State, Timeout} |
|
|
||||||
%% {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, Reply, State} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling call messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_call(_Request, _From, State) ->
|
handle_call(_Request, _From, State) ->
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_cast(Msg, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_info(Info, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling all non call/cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
Reply = ok, {reply, Reply, State}.
|
Reply = ok, {reply, Reply, State}.
|
||||||
|
|
||||||
handle_cast(_Msg, State) -> {noreply, State}.
|
handle_cast(_Msg, State) -> {noreply, State}.
|
||||||
@ -272,26 +244,18 @@ handle_info(refresh_iq_handlers, State) ->
|
|||||||
handle_info({timeout, _TRef, ID}, State) ->
|
handle_info({timeout, _TRef, ID}, State) ->
|
||||||
process_iq_timeout(ID),
|
process_iq_timeout(ID),
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
%%--------------------------------------------------------------------
|
handle_info(_Info, State) ->
|
||||||
%% Function: terminate(Reason, State) -> void()
|
{noreply, State}.
|
||||||
%% Description: This function is called by a gen_server when it is about to
|
|
||||||
%% terminate. It should be the opposite of Module:init/1 and do any necessary
|
terminate(_Reason, _State) ->
|
||||||
%% cleaning up. When it returns, the gen_server terminates with Reason.
|
ok.
|
||||||
%% The return value is ignored.
|
|
||||||
%%--------------------------------------------------------------------
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
%%--------------------------------------------------------------------
|
{ok, State}.
|
||||||
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
|
|
||||||
%% Description: Convert process state when code is changed
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
handle_info(_Info, State) -> {noreply, State}.
|
|
||||||
|
|
||||||
terminate(_Reason, _State) -> ok.
|
|
||||||
|
|
||||||
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
|
||||||
|
|
||||||
do_route(From, To, Packet) ->
|
do_route(From, To, Packet) ->
|
||||||
?DEBUG("local route~n\tfrom ~p~n\tto ~p~n\tpacket "
|
?DEBUG("local route~n\tfrom ~p~n\tto ~p~n\tpacket "
|
||||||
"~P~n",
|
"~P~n",
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
%%% @author Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
%%% @author Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
||||||
%%% @copyright (C) 2013, Evgeniy Khramtsov
|
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%%
|
%%%
|
||||||
%%% @end
|
%%% @end
|
||||||
|
@ -44,8 +44,8 @@
|
|||||||
to_bool/1,
|
to_bool/1,
|
||||||
sqlite_db/1,
|
sqlite_db/1,
|
||||||
sqlite_file/1,
|
sqlite_file/1,
|
||||||
encode_term/1,
|
encode_term/1,
|
||||||
decode_term/1,
|
decode_term/1,
|
||||||
odbc_config/0,
|
odbc_config/0,
|
||||||
freetds_config/0,
|
freetds_config/0,
|
||||||
odbcinst_config/0,
|
odbcinst_config/0,
|
||||||
@ -66,11 +66,11 @@
|
|||||||
|
|
||||||
-record(state,
|
-record(state,
|
||||||
{db_ref = self() :: pid(),
|
{db_ref = self() :: pid(),
|
||||||
db_type = odbc :: pgsql | mysql | sqlite | odbc | mssql,
|
db_type = odbc :: pgsql | mysql | sqlite | odbc | mssql,
|
||||||
start_interval = 0 :: non_neg_integer(),
|
start_interval = 0 :: non_neg_integer(),
|
||||||
host = <<"">> :: binary(),
|
host = <<"">> :: binary(),
|
||||||
max_pending_requests_len :: non_neg_integer(),
|
max_pending_requests_len :: non_neg_integer(),
|
||||||
pending_requests = {0, queue:new()} :: {non_neg_integer(), ?TQUEUE}}).
|
pending_requests = {0, queue:new()} :: {non_neg_integer(), ?TQUEUE}}).
|
||||||
|
|
||||||
-define(STATE_KEY, ejabberd_odbc_state).
|
-define(STATE_KEY, ejabberd_odbc_state).
|
||||||
|
|
||||||
@ -477,10 +477,6 @@ sql_query_internal(Query) ->
|
|||||||
pgsql ->
|
pgsql ->
|
||||||
pgsql_to_odbc(pgsql:squery(State#state.db_ref, Query));
|
pgsql_to_odbc(pgsql:squery(State#state.db_ref, Query));
|
||||||
mysql ->
|
mysql ->
|
||||||
?DEBUG("MySQL, Send query~n~p~n", [Query]),
|
|
||||||
%%squery to be able to specify result_type = binary
|
|
||||||
%%[Query] because p1_mysql_conn expect query to be a list (elements can be binaries, or iolist)
|
|
||||||
%% but doesn't accept just a binary
|
|
||||||
R = mysql_to_odbc(p1_mysql_conn:squery(State#state.db_ref,
|
R = mysql_to_odbc(p1_mysql_conn:squery(State#state.db_ref,
|
||||||
[Query], self(),
|
[Query], self(),
|
||||||
[{timeout, (?TRANSACTION_TIMEOUT) - 1000},
|
[{timeout, (?TRANSACTION_TIMEOUT) - 1000},
|
||||||
@ -614,14 +610,15 @@ pgsql_item_to_odbc(_) -> {updated, undefined}.
|
|||||||
%% Open a database connection to MySQL
|
%% Open a database connection to MySQL
|
||||||
mysql_connect(Server, Port, DB, Username, Password) ->
|
mysql_connect(Server, Port, DB, Username, Password) ->
|
||||||
case p1_mysql_conn:start(binary_to_list(Server), Port,
|
case p1_mysql_conn:start(binary_to_list(Server), Port,
|
||||||
binary_to_list(Username), binary_to_list(Password),
|
binary_to_list(Username),
|
||||||
binary_to_list(DB), fun log/3)
|
binary_to_list(Password),
|
||||||
|
binary_to_list(DB), fun log/3)
|
||||||
of
|
of
|
||||||
{ok, Ref} ->
|
{ok, Ref} ->
|
||||||
p1_mysql_conn:fetch(Ref, [<<"set names 'utf8';">>],
|
p1_mysql_conn:fetch(
|
||||||
self()),
|
Ref, [<<"set names 'utf8';">>], self()),
|
||||||
{ok, Ref};
|
{ok, Ref};
|
||||||
Err -> Err
|
Err -> Err
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Convert MySQL query result to Erlang ODBC result formalism
|
%% Convert MySQL query result to Erlang ODBC result formalism
|
||||||
@ -706,7 +703,7 @@ db_opts(Host) ->
|
|||||||
[odbc, <<"DSN=", Host/binary, ";UID=", Username/binary,
|
[odbc, <<"DSN=", Host/binary, ";UID=", Username/binary,
|
||||||
";PWD=", Pass/binary>>];
|
";PWD=", Pass/binary>>];
|
||||||
_ ->
|
_ ->
|
||||||
[Type, Server, Port, DB, User, Pass]
|
[Type, Server, Port, DB, User, Pass]
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
%%% Created : 17 Jul 2008 by Pablo Polvorin <pablo.polvorin@process-one.net>
|
%%% Created : 17 Jul 2008 by Pablo Polvorin <pablo.polvorin@process-one.net>
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
%%% @author Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
%%% @author Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
||||||
%%% @copyright (C) 2012, Evgeniy Khramtsov
|
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
@ -714,31 +713,9 @@ make_xinclude(Fn) ->
|
|||||||
Base = filename:basename(Fn),
|
Base = filename:basename(Fn),
|
||||||
io_lib:format("<xi:include href='~s'/>", [Base]).
|
io_lib:format("<xi:include href='~s'/>", [Base]).
|
||||||
|
|
||||||
%%%==================================
|
|
||||||
%%%% Export user
|
|
||||||
%% @spec (Fd, Username::string(), Host::string()) -> ok
|
|
||||||
%% @doc Extract user information and print it.
|
|
||||||
%% @spec (Username::string(), Host::string()) -> string()
|
|
||||||
%% @spec (InfoName::atom(), Username::string(), Host::string()) -> string()
|
|
||||||
%%%==================================
|
|
||||||
%%%% Interface with ejabberd offline storage
|
|
||||||
%% Copied from mod_offline.erl and customized
|
|
||||||
%%%==================================
|
|
||||||
%%%% Interface with ejabberd private storage
|
|
||||||
%%%==================================
|
|
||||||
%%%% Disk file access
|
|
||||||
%% @spec () -> string()
|
|
||||||
%% @spec (Dir::string(), FnT::string()) -> string()
|
|
||||||
%% @spec (FnT::string(), Host::string()) -> FnH::string()
|
|
||||||
%% @doc Make the filename for the host.
|
|
||||||
%% Example: ``("20080804-231550", "jabber.example.org") -> "20080804-231550_jabber_example_org.xml"''
|
|
||||||
%% @spec (Fn::string()) -> {ok, Fd}
|
|
||||||
%% @spec (Fd) -> ok
|
|
||||||
%% @spec (Fd, String::string()) -> ok
|
|
||||||
print(Fd, String) ->
|
print(Fd, String) ->
|
||||||
%%%==================================
|
|
||||||
%%% vim: set filetype=erlang tabstop=8 foldmarker=%%%%,%%%= foldmethod=marker:
|
|
||||||
file:write(Fd, String).
|
file:write(Fd, String).
|
||||||
|
|
||||||
opt_type(auth_password_format) -> fun (X) -> X end;
|
opt_type(auth_password_format) -> fun (X) -> X end;
|
||||||
opt_type(_) -> [auth_password_format].
|
opt_type(_) -> [auth_password_format].
|
||||||
|
|
||||||
|
@ -58,13 +58,6 @@
|
|||||||
|
|
||||||
-define(HIBERNATE_TIMEOUT, 90000).
|
-define(HIBERNATE_TIMEOUT, 90000).
|
||||||
|
|
||||||
%%====================================================================
|
|
||||||
%% API
|
|
||||||
%%====================================================================
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
|
|
||||||
%% Description: Starts the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
-spec start_link(inet:socket(), atom(), shaper:shaper(),
|
-spec start_link(inet:socket(), atom(), shaper:shaper(),
|
||||||
non_neg_integer() | infinity) -> ignore |
|
non_neg_integer() | infinity) -> ignore |
|
||||||
{error, any()} |
|
{error, any()} |
|
||||||
@ -76,10 +69,6 @@ start_link(Socket, SockMod, Shaper, MaxStanzaSize) ->
|
|||||||
|
|
||||||
-spec start(inet:socket(), atom(), shaper:shaper()) -> undefined | pid().
|
-spec start(inet:socket(), atom(), shaper:shaper()) -> undefined | pid().
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: start() -> {ok,Pid} | ignore | {error,Error}
|
|
||||||
%% Description: Starts the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
start(Socket, SockMod, Shaper) ->
|
start(Socket, SockMod, Shaper) ->
|
||||||
start(Socket, SockMod, Shaper, infinity).
|
start(Socket, SockMod, Shaper, infinity).
|
||||||
|
|
||||||
@ -127,13 +116,6 @@ close(Pid) ->
|
|||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: init(Args) -> {ok, State} |
|
|
||||||
%% {ok, State, Timeout} |
|
|
||||||
%% ignore |
|
|
||||||
%% {stop, Reason}
|
|
||||||
%% Description: Initiates the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
init([Socket, SockMod, Shaper, MaxStanzaSize]) ->
|
init([Socket, SockMod, Shaper, MaxStanzaSize]) ->
|
||||||
ShaperState = shaper:new(Shaper),
|
ShaperState = shaper:new(Shaper),
|
||||||
Timeout = case SockMod of
|
Timeout = case SockMod of
|
||||||
@ -145,15 +127,6 @@ init([Socket, SockMod, Shaper, MaxStanzaSize]) ->
|
|||||||
shaper_state = ShaperState,
|
shaper_state = ShaperState,
|
||||||
max_stanza_size = MaxStanzaSize, timeout = Timeout}}.
|
max_stanza_size = MaxStanzaSize, timeout = Timeout}}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
|
|
||||||
%% {reply, Reply, State, Timeout} |
|
|
||||||
%% {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, Reply, State} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling call messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_call({starttls, TLSSocket}, _From,
|
handle_call({starttls, TLSSocket}, _From,
|
||||||
#state{xml_stream_state = XMLStreamState,
|
#state{xml_stream_state = XMLStreamState,
|
||||||
c2s_pid = C2SPid,
|
c2s_pid = C2SPid,
|
||||||
@ -163,15 +136,15 @@ handle_call({starttls, TLSSocket}, _From,
|
|||||||
undefined ->
|
undefined ->
|
||||||
XMLStreamState;
|
XMLStreamState;
|
||||||
_ ->
|
_ ->
|
||||||
xml_stream:new(C2SPid,
|
xml_stream:new(C2SPid, MaxStanzaSize)
|
||||||
MaxStanzaSize)
|
|
||||||
end,
|
end,
|
||||||
NewState = State#state{socket = TLSSocket,
|
NewState = State#state{socket = TLSSocket,
|
||||||
sock_mod = p1_tls,
|
sock_mod = p1_tls,
|
||||||
xml_stream_state = NewXMLStreamState},
|
xml_stream_state = NewXMLStreamState},
|
||||||
case p1_tls:recv_data(TLSSocket, <<"">>) of
|
case p1_tls:recv_data(TLSSocket, <<"">>) of
|
||||||
{ok, TLSData} ->
|
{ok, TLSData} ->
|
||||||
{reply, ok, process_data(TLSData, NewState), ?HIBERNATE_TIMEOUT};
|
{reply, ok,
|
||||||
|
process_data(TLSData, NewState), ?HIBERNATE_TIMEOUT};
|
||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
{stop, normal, ok, NewState}
|
{stop, normal, ok, NewState}
|
||||||
end;
|
end;
|
||||||
@ -186,24 +159,23 @@ handle_call({compress, Data}, _From,
|
|||||||
true -> ok
|
true -> ok
|
||||||
end,
|
end,
|
||||||
close_stream(XMLStreamState),
|
close_stream(XMLStreamState),
|
||||||
NewXMLStreamState = xml_stream:new(C2SPid,
|
NewXMLStreamState = xml_stream:new(C2SPid, MaxStanzaSize),
|
||||||
MaxStanzaSize),
|
|
||||||
NewState = State#state{socket = ZlibSocket,
|
NewState = State#state{socket = ZlibSocket,
|
||||||
sock_mod = ezlib,
|
sock_mod = ezlib,
|
||||||
xml_stream_state = NewXMLStreamState},
|
xml_stream_state = NewXMLStreamState},
|
||||||
case ezlib:recv_data(ZlibSocket, <<"">>) of
|
case ezlib:recv_data(ZlibSocket, <<"">>) of
|
||||||
{ok, ZlibData} ->
|
{ok, ZlibData} ->
|
||||||
{reply, {ok, ZlibSocket},
|
{reply, {ok, ZlibSocket},
|
||||||
process_data(ZlibData, NewState), ?HIBERNATE_TIMEOUT};
|
process_data(ZlibData, NewState), ?HIBERNATE_TIMEOUT};
|
||||||
{error, _Reason} -> {stop, normal, ok, NewState}
|
{error, _Reason} ->
|
||||||
|
{stop, normal, ok, NewState}
|
||||||
end;
|
end;
|
||||||
handle_call(reset_stream, _From,
|
handle_call(reset_stream, _From,
|
||||||
#state{xml_stream_state = XMLStreamState,
|
#state{xml_stream_state = XMLStreamState,
|
||||||
c2s_pid = C2SPid, max_stanza_size = MaxStanzaSize} =
|
c2s_pid = C2SPid, max_stanza_size = MaxStanzaSize} =
|
||||||
State) ->
|
State) ->
|
||||||
close_stream(XMLStreamState),
|
close_stream(XMLStreamState),
|
||||||
NewXMLStreamState = xml_stream:new(C2SPid,
|
NewXMLStreamState = xml_stream:new(C2SPid, MaxStanzaSize),
|
||||||
MaxStanzaSize),
|
|
||||||
Reply = ok,
|
Reply = ok,
|
||||||
{reply, Reply,
|
{reply, Reply,
|
||||||
State#state{xml_stream_state = NewXMLStreamState},
|
State#state{xml_stream_state = NewXMLStreamState},
|
||||||
@ -218,12 +190,6 @@ handle_call({become_controller, C2SPid}, _From, State) ->
|
|||||||
handle_call(_Request, _From, State) ->
|
handle_call(_Request, _From, State) ->
|
||||||
Reply = ok, {reply, Reply, State, ?HIBERNATE_TIMEOUT}.
|
Reply = ok, {reply, Reply, State, ?HIBERNATE_TIMEOUT}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_cast(Msg, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_cast({change_shaper, Shaper}, State) ->
|
handle_cast({change_shaper, Shaper}, State) ->
|
||||||
NewShaperState = shaper:new(Shaper),
|
NewShaperState = shaper:new(Shaper),
|
||||||
{noreply, State#state{shaper_state = NewShaperState},
|
{noreply, State#state{shaper_state = NewShaperState},
|
||||||
@ -232,12 +198,6 @@ handle_cast(close, State) -> {stop, normal, State};
|
|||||||
handle_cast(_Msg, State) ->
|
handle_cast(_Msg, State) ->
|
||||||
{noreply, State, ?HIBERNATE_TIMEOUT}.
|
{noreply, State, ?HIBERNATE_TIMEOUT}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_info(Info, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling all non call/cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_info({Tag, _TCPSocket, Data},
|
handle_info({Tag, _TCPSocket, Data},
|
||||||
#state{socket = Socket, sock_mod = SockMod} = State)
|
#state{socket = Socket, sock_mod = SockMod} = State)
|
||||||
when (Tag == tcp) or (Tag == ssl) or
|
when (Tag == tcp) or (Tag == ssl) or
|
||||||
@ -285,13 +245,6 @@ handle_info(timeout, State) ->
|
|||||||
handle_info(_Info, State) ->
|
handle_info(_Info, State) ->
|
||||||
{noreply, State, ?HIBERNATE_TIMEOUT}.
|
{noreply, State, ?HIBERNATE_TIMEOUT}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: terminate(Reason, State) -> void()
|
|
||||||
%% Description: This function is called by a gen_server when it is about to
|
|
||||||
%% terminate. It should be the opposite of Module:init/1 and do any necessary
|
|
||||||
%% cleaning up. When it returns, the gen_server terminates with Reason.
|
|
||||||
%% The return value is ignored.
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
terminate(_Reason,
|
terminate(_Reason,
|
||||||
#state{xml_stream_state = XMLStreamState,
|
#state{xml_stream_state = XMLStreamState,
|
||||||
c2s_pid = C2SPid} =
|
c2s_pid = C2SPid} =
|
||||||
@ -304,10 +257,6 @@ terminate(_Reason,
|
|||||||
catch (State#state.sock_mod):close(State#state.socket),
|
catch (State#state.sock_mod):close(State#state.socket),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
|
|
||||||
%% Description: Convert process state when code is changed
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
%%% Created : 29 Dec 2011 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 29 Dec 2011 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%% @copyright (C) 2002-2015 ProcessOne
|
%%% @copyright (C) 2002-2015 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
|
%%% ejabberd, Copyright (C) 2002-2015 ProcessOne
|
||||||
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
%%% published by the Free Software Foundation; either version 2 of the
|
%%% published by the Free Software Foundation; either version 2 of the
|
||||||
|
@ -226,7 +226,8 @@ dirty_get_all_domains() ->
|
|||||||
init([]) ->
|
init([]) ->
|
||||||
update_tables(),
|
update_tables(),
|
||||||
mnesia:create_table(route,
|
mnesia:create_table(route,
|
||||||
[{ram_copies, [node()]}, {type, bag},
|
[{ram_copies, [node()]},
|
||||||
|
{type, bag},
|
||||||
{attributes, record_info(fields, route)}]),
|
{attributes, record_info(fields, route)}]),
|
||||||
mnesia:add_table_copy(route, node(), ram_copies),
|
mnesia:add_table_copy(route, node(), ram_copies),
|
||||||
mnesia:subscribe({table, route, simple}),
|
mnesia:subscribe({table, route, simple}),
|
||||||
|
@ -3,6 +3,24 @@
|
|||||||
%%% Author : Badlop <badlop@process-one.net>
|
%%% Author : Badlop <badlop@process-one.net>
|
||||||
%%% Purpose : Multicast router
|
%%% Purpose : Multicast router
|
||||||
%%% Created : 11 Aug 2007 by Badlop <badlop@process-one.net>
|
%%% Created : 11 Aug 2007 by Badlop <badlop@process-one.net>
|
||||||
|
%%%
|
||||||
|
%%%
|
||||||
|
%%% ejabberd, Copyright (C) 2002-2015 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(ejabberd_router_multicast).
|
-module(ejabberd_router_multicast).
|
||||||
|
@ -85,13 +85,6 @@
|
|||||||
|
|
||||||
-type temporarily_blocked() :: #temporarily_blocked{}.
|
-type temporarily_blocked() :: #temporarily_blocked{}.
|
||||||
|
|
||||||
%%====================================================================
|
|
||||||
%% API
|
|
||||||
%%====================================================================
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
|
|
||||||
%% Description: Starts the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
start_link() ->
|
start_link() ->
|
||||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [],
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [],
|
||||||
[]).
|
[]).
|
||||||
@ -162,7 +155,7 @@ remove_connection(FromTo, Pid, Key) ->
|
|||||||
|
|
||||||
have_connection(FromTo) ->
|
have_connection(FromTo) ->
|
||||||
case catch mnesia:dirty_read(s2s, FromTo) of
|
case catch mnesia:dirty_read(s2s, FromTo) of
|
||||||
[_] ->
|
[_] ->
|
||||||
true;
|
true;
|
||||||
_ ->
|
_ ->
|
||||||
false
|
false
|
||||||
@ -251,51 +244,26 @@ check_peer_certificate(SockMod, Sock, Peer) ->
|
|||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: init(Args) -> {ok, State} |
|
|
||||||
%% {ok, State, Timeout} |
|
|
||||||
%% ignore |
|
|
||||||
%% {stop, Reason}
|
|
||||||
%% Description: Initiates the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
init([]) ->
|
init([]) ->
|
||||||
update_tables(),
|
update_tables(),
|
||||||
mnesia:create_table(s2s, [{ram_copies, [node()]}, {type, bag},
|
mnesia:create_table(s2s,
|
||||||
{attributes, record_info(fields, s2s)}]),
|
[{ram_copies, [node()]},
|
||||||
|
{type, bag},
|
||||||
|
{attributes, record_info(fields, s2s)}]),
|
||||||
mnesia:add_table_copy(s2s, node(), ram_copies),
|
mnesia:add_table_copy(s2s, node(), ram_copies),
|
||||||
mnesia:subscribe(system),
|
mnesia:subscribe(system),
|
||||||
ejabberd_commands:register_commands(commands()),
|
ejabberd_commands:register_commands(commands()),
|
||||||
mnesia:create_table(temporarily_blocked, [{ram_copies, [node()]}, {attributes, record_info(fields, temporarily_blocked)}]),
|
mnesia:create_table(temporarily_blocked,
|
||||||
|
[{ram_copies, [node()]},
|
||||||
|
{attributes, record_info(fields, temporarily_blocked)}]),
|
||||||
{ok, #state{}}.
|
{ok, #state{}}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
|
|
||||||
%% {reply, Reply, State, Timeout} |
|
|
||||||
%% {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, Reply, State} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling call messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_call(_Request, _From, State) ->
|
handle_call(_Request, _From, State) ->
|
||||||
Reply = ok,
|
{reply, ok, State}.
|
||||||
{reply, Reply, State}.
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_cast(Msg, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_cast(_Msg, State) ->
|
handle_cast(_Msg, State) ->
|
||||||
{noreply, State}.
|
{noreply, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_info(Info, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling all non call/cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_info({mnesia_system_event, {mnesia_down, Node}}, State) ->
|
handle_info({mnesia_system_event, {mnesia_down, Node}}, State) ->
|
||||||
clean_table_from_bad_node(Node),
|
clean_table_from_bad_node(Node),
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
@ -309,27 +277,17 @@ handle_info({route, From, To, Packet}, State) ->
|
|||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_info(_Info, State) -> {noreply, State}.
|
handle_info(_Info, State) -> {noreply, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: terminate(Reason, State) -> void()
|
|
||||||
%% Description: This function is called by a gen_server when it is about to
|
|
||||||
%% terminate. It should be the opposite of Module:init/1 and do any necessary
|
|
||||||
%% cleaning up. When it returns, the gen_server terminates with Reason.
|
|
||||||
%% The return value is ignored.
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
terminate(_Reason, _State) ->
|
terminate(_Reason, _State) ->
|
||||||
ejabberd_commands:unregister_commands(commands()),
|
ejabberd_commands:unregister_commands(commands()),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
|
|
||||||
%% Description: Convert process state when code is changed
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
code_change(_OldVsn, State, _Extra) ->
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
clean_table_from_bad_node(Node) ->
|
clean_table_from_bad_node(Node) ->
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
Es = mnesia:select(
|
Es = mnesia:select(
|
||||||
@ -520,7 +478,8 @@ parent_domains(Domain) ->
|
|||||||
end,
|
end,
|
||||||
[], lists:reverse(str:tokens(Domain, <<".">>))).
|
[], lists:reverse(str:tokens(Domain, <<".">>))).
|
||||||
|
|
||||||
send_element(Pid, El) -> Pid ! {send_element, El}.
|
send_element(Pid, El) ->
|
||||||
|
Pid ! {send_element, El}.
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% ejabberd commands
|
%%% ejabberd commands
|
||||||
@ -566,10 +525,8 @@ update_tables() ->
|
|||||||
{'EXIT', _} -> ok
|
{'EXIT', _} -> ok
|
||||||
end,
|
end,
|
||||||
case lists:member(local_s2s, mnesia:system_info(tables)) of
|
case lists:member(local_s2s, mnesia:system_info(tables)) of
|
||||||
true ->
|
true -> mnesia:delete_table(local_s2s);
|
||||||
mnesia:delete_table(local_s2s);
|
false -> ok
|
||||||
false ->
|
|
||||||
ok
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Check if host is in blacklist or white list
|
%% Check if host is in blacklist or white list
|
||||||
|
@ -111,9 +111,6 @@
|
|||||||
-define(INVALID_XML_ERR,
|
-define(INVALID_XML_ERR,
|
||||||
xml:element_to_binary(?SERR_XML_NOT_WELL_FORMED)).
|
xml:element_to_binary(?SERR_XML_NOT_WELL_FORMED)).
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%% API
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
start(SockData, Opts) -> ?SUPERVISOR_START.
|
start(SockData, Opts) -> ?SUPERVISOR_START.
|
||||||
|
|
||||||
start_link(SockData, Opts) ->
|
start_link(SockData, Opts) ->
|
||||||
@ -126,13 +123,6 @@ socket_type() -> xml_stream.
|
|||||||
%%% Callback functions from gen_fsm
|
%%% Callback functions from gen_fsm
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: init/1
|
|
||||||
%% Returns: {ok, StateName, StateData} |
|
|
||||||
%% {ok, StateName, StateData, Timeout} |
|
|
||||||
%% ignore |
|
|
||||||
%% {stop, StopReason}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
init([{SockMod, Socket}, Opts]) ->
|
init([{SockMod, Socket}, Opts]) ->
|
||||||
?DEBUG("started: ~p", [{SockMod, Socket}]),
|
?DEBUG("started: ~p", [{SockMod, Socket}]),
|
||||||
Shaper = case lists:keysearch(shaper, 1, Opts) of
|
Shaper = case lists:keysearch(shaper, 1, Opts) of
|
||||||
@ -567,20 +557,8 @@ stream_established(closed, StateData) ->
|
|||||||
% Reply = ok,
|
% Reply = ok,
|
||||||
% {reply, Reply, state_name, StateData}.
|
% {reply, Reply, state_name, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_event/3
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
handle_event(_Event, StateName, StateData) ->
|
handle_event(_Event, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData}.
|
{next_state, StateName, StateData}.
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_sync_event/4
|
|
||||||
%% Returns: The associated StateData for this connection
|
|
||||||
%% {reply, Reply, NextStateName, NextStateData}
|
|
||||||
%% Reply = {state_infos, [{InfoName::atom(), InfoValue::any()]
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
handle_sync_event(get_state_infos, _From, StateName,
|
handle_sync_event(get_state_infos, _From, StateName,
|
||||||
StateData) ->
|
StateData) ->
|
||||||
@ -621,12 +599,6 @@ handle_sync_event(_Event, _From, StateName,
|
|||||||
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
||||||
{ok, StateName, StateData}.
|
{ok, StateName, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_info/3
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
handle_info({send_text, Text}, StateName, StateData) ->
|
handle_info({send_text, Text}, StateName, StateData) ->
|
||||||
send_text(StateData, Text),
|
send_text(StateData, Text),
|
||||||
{next_state, StateName, StateData};
|
{next_state, StateName, StateData};
|
||||||
@ -636,11 +608,6 @@ handle_info({timeout, Timer, _}, _StateName,
|
|||||||
handle_info(_, StateName, StateData) ->
|
handle_info(_, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData}.
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: terminate/3
|
|
||||||
%% Purpose: Shutdown the fsm
|
|
||||||
%% Returns: any
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
terminate(Reason, _StateName, StateData) ->
|
terminate(Reason, _StateName, StateData) ->
|
||||||
?DEBUG("terminated: ~p", [Reason]),
|
?DEBUG("terminated: ~p", [Reason]),
|
||||||
case Reason of
|
case Reason of
|
||||||
@ -661,11 +628,6 @@ get_external_hosts(StateData) ->
|
|||||||
|| {{D, _}, established} <- dict:to_list(Connections)]
|
|| {{D, _}, established} <- dict:to_list(Connections)]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: print_state/1
|
|
||||||
%% Purpose: Prepare the state to be printed on error log
|
|
||||||
%% Returns: State to print
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
print_state(State) -> State.
|
print_state(State) -> State.
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
start_connection/1,
|
start_connection/1,
|
||||||
terminate_if_waiting_delay/2,
|
terminate_if_waiting_delay/2,
|
||||||
stop_connection/1,
|
stop_connection/1,
|
||||||
transform_options/1]).
|
transform_options/1]).
|
||||||
|
|
||||||
-export([init/1, open_socket/2, wait_for_stream/2,
|
-export([init/1, open_socket/2, wait_for_stream/2,
|
||||||
wait_for_validation/2, wait_for_features/2,
|
wait_for_validation/2, wait_for_features/2,
|
||||||
@ -141,13 +141,6 @@ stop_connection(Pid) -> p1_fsm:send_event(Pid, closed).
|
|||||||
%%% Callback functions from p1_fsm
|
%%% Callback functions from p1_fsm
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: init/1
|
|
||||||
%% Returns: {ok, StateName, StateData} |
|
|
||||||
%% {ok, StateName, StateData, Timeout} |
|
|
||||||
%% ignore |
|
|
||||||
%% {stop, StopReason}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
init([From, Server, Type]) ->
|
init([From, Server, Type]) ->
|
||||||
process_flag(trap_exit, true),
|
process_flag(trap_exit, true),
|
||||||
?DEBUG("started: ~p", [{From, Server, Type}]),
|
?DEBUG("started: ~p", [{From, Server, Type}]),
|
||||||
@ -222,12 +215,6 @@ init([From, Server, Type]) ->
|
|||||||
tls_options = TLSOpts, queue = queue:new(), myname = From,
|
tls_options = TLSOpts, queue = queue:new(), myname = From,
|
||||||
server = Server, new = New, verify = Verify, timer = Timer}}.
|
server = Server, new = New, verify = Verify, timer = Timer}}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: StateName/2
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
open_socket(init, StateData) ->
|
open_socket(init, StateData) ->
|
||||||
log_s2s_out(StateData#state.new, StateData#state.myname,
|
log_s2s_out(StateData#state.new, StateData#state.myname,
|
||||||
StateData#state.server, StateData#state.tls),
|
StateData#state.server, StateData#state.tls),
|
||||||
@ -292,8 +279,6 @@ open_socket(timeout, StateData) ->
|
|||||||
open_socket(_, StateData) ->
|
open_socket(_, StateData) ->
|
||||||
{next_state, open_socket, StateData}.
|
{next_state, open_socket, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% IPv4
|
|
||||||
open_socket1({_, _, _, _} = Addr, Port) ->
|
open_socket1({_, _, _, _} = Addr, Port) ->
|
||||||
open_socket2(inet, Addr, Port);
|
open_socket2(inet, Addr, Port);
|
||||||
%% IPv6
|
%% IPv6
|
||||||
@ -872,19 +857,7 @@ stream_established(closed, StateData) ->
|
|||||||
%% Reply = ok,
|
%% Reply = ok,
|
||||||
%% {reply, Reply, state_name, StateData}.
|
%% {reply, Reply, state_name, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_event/3
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
handle_event(_Event, StateName, StateData) ->
|
handle_event(_Event, StateName, StateData) ->
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_sync_event/4
|
|
||||||
%% Returns: The associated StateData for this connection
|
|
||||||
%% {reply, Reply, NextStateName, NextStateData}
|
|
||||||
%% Reply = {state_infos, [{InfoName::atom(), InfoValue::any()]
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
{next_state, StateName, StateData,
|
{next_state, StateName, StateData,
|
||||||
get_timeout_interval(StateName)}.
|
get_timeout_interval(StateName)}.
|
||||||
|
|
||||||
@ -933,12 +906,6 @@ handle_sync_event(_Event, _From, StateName,
|
|||||||
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
||||||
{ok, StateName, StateData}.
|
{ok, StateName, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_info/3
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
handle_info({send_text, Text}, StateName, StateData) ->
|
handle_info({send_text, Text}, StateName, StateData) ->
|
||||||
send_text(StateData, Text),
|
send_text(StateData, Text),
|
||||||
cancel_timer(StateData#state.timer),
|
cancel_timer(StateData#state.timer),
|
||||||
@ -995,11 +962,6 @@ handle_info(_, StateName, StateData) ->
|
|||||||
{next_state, StateName, StateData,
|
{next_state, StateName, StateData,
|
||||||
get_timeout_interval(StateName)}.
|
get_timeout_interval(StateName)}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: terminate/3
|
|
||||||
%% Purpose: Shutdown the fsm
|
|
||||||
%% Returns: any
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
terminate(Reason, StateName, StateData) ->
|
terminate(Reason, StateName, StateData) ->
|
||||||
?DEBUG("terminated: ~p", [{Reason, StateName}]),
|
?DEBUG("terminated: ~p", [{Reason, StateName}]),
|
||||||
case StateData#state.new of
|
case StateData#state.new of
|
||||||
@ -1018,11 +980,6 @@ terminate(Reason, StateName, StateData) ->
|
|||||||
end,
|
end,
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: print_state/1
|
|
||||||
%% Purpose: Prepare the state to be printed on error log
|
|
||||||
%% Returns: State to print
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
print_state(State) -> State.
|
print_state(State) -> State.
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
@ -1328,10 +1285,6 @@ wait_before_reconnect(StateData) ->
|
|||||||
D1 -> lists:min([D1 * 2, get_max_retry_delay()])
|
D1 -> lists:min([D1 * 2, get_max_retry_delay()])
|
||||||
end,
|
end,
|
||||||
Timer = erlang:start_timer(Delay, self(), []),
|
Timer = erlang:start_timer(Delay, self(), []),
|
||||||
%% @doc Get the maximum allowed delay for retry to reconnect (in miliseconds).
|
|
||||||
%% The default value is 5 minutes.
|
|
||||||
%% The option {s2s_max_retry_delay, Seconds} can be used (in seconds).
|
|
||||||
%% @spec () -> integer()
|
|
||||||
{next_state, wait_before_retry,
|
{next_state, wait_before_retry,
|
||||||
StateData#state{timer = Timer, delay_to_retry = Delay,
|
StateData#state{timer = Timer, delay_to_retry = Delay,
|
||||||
queue = queue:new()}}.
|
queue = queue:new()}}.
|
||||||
|
@ -95,10 +95,6 @@
|
|||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% API
|
%% API
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
|
|
||||||
%% Description: Starts the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
-export_type([sid/0]).
|
-export_type([sid/0]).
|
||||||
|
|
||||||
start() ->
|
start() ->
|
||||||
@ -107,8 +103,7 @@ start() ->
|
|||||||
supervisor:start_child(ejabberd_sup, ChildSpec).
|
supervisor:start_child(ejabberd_sup, ChildSpec).
|
||||||
|
|
||||||
start_link() ->
|
start_link() ->
|
||||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [],
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||||
[]).
|
|
||||||
|
|
||||||
-spec route(jid(), jid(), xmlel() | broadcast()) -> ok.
|
-spec route(jid(), jid(), xmlel() | broadcast()) -> ok.
|
||||||
|
|
||||||
@ -149,6 +144,9 @@ close_session(SID, User, Server, Resource) ->
|
|||||||
ejabberd_hooks:run(sm_remove_connection_hook,
|
ejabberd_hooks:run(sm_remove_connection_hook,
|
||||||
JID#jid.lserver, [SID, JID, Info]).
|
JID#jid.lserver, [SID, JID, Info]).
|
||||||
|
|
||||||
|
-spec check_in_subscription(any(), binary(), binary(),
|
||||||
|
any(), any(), any()) -> any().
|
||||||
|
|
||||||
check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) ->
|
check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) ->
|
||||||
case ejabberd_auth:is_user_exists(User, Server) of
|
case ejabberd_auth:is_user_exists(User, Server) of
|
||||||
true -> Acc;
|
true -> Acc;
|
||||||
@ -268,6 +266,8 @@ dirty_get_sessions_list() ->
|
|||||||
Mod = get_sm_backend(),
|
Mod = get_sm_backend(),
|
||||||
[S#session.usr || S <- Mod:get_sessions()].
|
[S#session.usr || S <- Mod:get_sessions()].
|
||||||
|
|
||||||
|
-spec dirty_get_my_sessions_list() -> [#session{}].
|
||||||
|
|
||||||
dirty_get_my_sessions_list() ->
|
dirty_get_my_sessions_list() ->
|
||||||
Mod = get_sm_backend(),
|
Mod = get_sm_backend(),
|
||||||
[S || S <- Mod:get_sessions(), node(element(2, S#session.sid)) == node()].
|
[S || S <- Mod:get_sessions(), node(element(2, S#session.sid)) == node()].
|
||||||
@ -285,20 +285,20 @@ get_all_pids() ->
|
|||||||
Mod = get_sm_backend(),
|
Mod = get_sm_backend(),
|
||||||
[element(2, S#session.sid) || S <- Mod:get_sessions()].
|
[element(2, S#session.sid) || S <- Mod:get_sessions()].
|
||||||
|
|
||||||
|
-spec get_vh_session_number(binary()) -> non_neg_integer().
|
||||||
|
|
||||||
get_vh_session_number(Server) ->
|
get_vh_session_number(Server) ->
|
||||||
LServer = jlib:nameprep(Server),
|
LServer = jlib:nameprep(Server),
|
||||||
Mod = get_sm_backend(),
|
Mod = get_sm_backend(),
|
||||||
length(Mod:get_sessions(LServer)).
|
length(Mod:get_sessions(LServer)).
|
||||||
|
|
||||||
register_iq_handler(Host, XMLNS, Module, Fun) ->
|
register_iq_handler(Host, XMLNS, Module, Fun) ->
|
||||||
ejabberd_sm !
|
ejabberd_sm ! {register_iq_handler, Host, XMLNS, Module, Fun}.
|
||||||
{register_iq_handler, Host, XMLNS, Module, Fun}.
|
|
||||||
|
|
||||||
-spec register_iq_handler(binary(), binary(), atom(), atom(), list()) -> any().
|
-spec register_iq_handler(binary(), binary(), atom(), atom(), list()) -> any().
|
||||||
|
|
||||||
register_iq_handler(Host, XMLNS, Module, Fun, Opts) ->
|
register_iq_handler(Host, XMLNS, Module, Fun, Opts) ->
|
||||||
ejabberd_sm !
|
ejabberd_sm ! {register_iq_handler, Host, XMLNS, Module, Fun, Opts}.
|
||||||
{register_iq_handler, Host, XMLNS, Module, Fun, Opts}.
|
|
||||||
|
|
||||||
-spec unregister_iq_handler(binary(), binary()) -> any().
|
-spec unregister_iq_handler(binary(), binary()) -> any().
|
||||||
|
|
||||||
@ -310,13 +310,6 @@ unregister_iq_handler(Host, XMLNS) ->
|
|||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: init(Args) -> {ok, State} |
|
|
||||||
%% {ok, State, Timeout} |
|
|
||||||
%% ignore |
|
|
||||||
%% {stop, Reason}
|
|
||||||
%% Description: Initiates the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
init([]) ->
|
init([]) ->
|
||||||
Mod = get_sm_backend(),
|
Mod = get_sm_backend(),
|
||||||
Mod:init(),
|
Mod:init(),
|
||||||
@ -333,32 +326,11 @@ init([]) ->
|
|||||||
ejabberd_commands:register_commands(commands()),
|
ejabberd_commands:register_commands(commands()),
|
||||||
{ok, #state{}}.
|
{ok, #state{}}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
|
|
||||||
%% {reply, Reply, State, Timeout} |
|
|
||||||
%% {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, Reply, State} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling call messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_call(_Request, _From, State) ->
|
handle_call(_Request, _From, State) ->
|
||||||
Reply = ok, {reply, Reply, State}.
|
Reply = ok, {reply, Reply, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_cast(Msg, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_cast(_Msg, State) -> {noreply, State}.
|
handle_cast(_Msg, State) -> {noreply, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_info(Info, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling all non call/cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_info({route, From, To, Packet}, State) ->
|
handle_info({route, From, To, Packet}, State) ->
|
||||||
case catch do_route(From, To, Packet) of
|
case catch do_route(From, To, Packet) of
|
||||||
{'EXIT', Reason} ->
|
{'EXIT', Reason} ->
|
||||||
@ -388,27 +360,19 @@ handle_info({unregister_iq_handler, Host, XMLNS},
|
|||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_info(_Info, State) -> {noreply, State}.
|
handle_info(_Info, State) -> {noreply, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: terminate(Reason, State) -> void()
|
|
||||||
%% Description: This function is called by a gen_server when it is about to
|
|
||||||
%% terminate. It should be the opposite of Module:init/1 and do any necessary
|
|
||||||
%% cleaning up. When it returns, the gen_server terminates with Reason.
|
|
||||||
%% The return value is ignored.
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
terminate(_Reason, _State) ->
|
terminate(_Reason, _State) ->
|
||||||
ejabberd_commands:unregister_commands(commands()),
|
ejabberd_commands:unregister_commands(commands()),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
|
|
||||||
%% Description: Convert process state when code is changed
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-spec set_session(sid(), binary(), binary(), binary(),
|
||||||
|
prio(), info()) -> ok.
|
||||||
|
|
||||||
set_session(SID, User, Server, Resource, Priority, Info) ->
|
set_session(SID, User, Server, Resource, Priority, Info) ->
|
||||||
LUser = jlib:nodeprep(User),
|
LUser = jlib:nodeprep(User),
|
||||||
LServer = jlib:nameprep(Server),
|
LServer = jlib:nameprep(Server),
|
||||||
|
@ -131,7 +131,8 @@ get_sessions(LUser, LServer) ->
|
|||||||
[]
|
[]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec get_sessions(binary(), binary(), binary()) -> [#session{}].
|
-spec get_sessions(binary(), binary(), binary()) ->
|
||||||
|
[#session{}].
|
||||||
get_sessions(LUser, LServer, LResource) ->
|
get_sessions(LUser, LServer, LResource) ->
|
||||||
USKey = us_to_key({LUser, LServer}),
|
USKey = us_to_key({LUser, LServer}),
|
||||||
case eredis:q(?PROCNAME, ["HGETALL", USKey]) of
|
case eredis:q(?PROCNAME, ["HGETALL", USKey]) of
|
||||||
|
@ -67,15 +67,12 @@
|
|||||||
|
|
||||||
-export_type([socket_state/0, sockmod/0]).
|
-export_type([socket_state/0, sockmod/0]).
|
||||||
|
|
||||||
-spec start(atom(), sockmod(), socket(), [{atom(), any()}]) -> any().
|
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% API
|
%% API
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%%--------------------------------------------------------------------
|
-spec start(atom(), sockmod(), socket(), [{atom(), any()}]) -> any().
|
||||||
%% Function:
|
|
||||||
%% Description:
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
start(Module, SockMod, Socket, Opts) ->
|
start(Module, SockMod, Socket, Opts) ->
|
||||||
case Module:socket_type() of
|
case Module:socket_type() of
|
||||||
xml_stream ->
|
xml_stream ->
|
||||||
@ -241,7 +238,3 @@ peername(#socket_state{sockmod = SockMod,
|
|||||||
_ -> SockMod:peername(Socket)
|
_ -> SockMod:peername(Socket)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%%====================================================================
|
|
||||||
%% Internal functions
|
|
||||||
%%====================================================================
|
|
||||||
%====================================================================
|
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([start_link/0, process_command/3,
|
-export([start_link/0, process_command/3, register_hook/1,
|
||||||
process_remote_command/1]).
|
process_remote_command/1]).
|
||||||
|
|
||||||
-export([init/1, handle_call/3, handle_cast/2,
|
-export([init/1, handle_call/3, handle_cast/2,
|
||||||
@ -85,6 +85,10 @@ process_command(From, To, Packet) ->
|
|||||||
_ -> ok
|
_ -> ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
register_hook(Host) ->
|
||||||
|
ejabberd_hooks:add(local_send_to_resource_hook, Host,
|
||||||
|
?MODULE, process_command, 50).
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
@ -100,11 +104,7 @@ init(Opts) ->
|
|||||||
LH = proplists:get_value(large_heap, Opts),
|
LH = proplists:get_value(large_heap, Opts),
|
||||||
process_flag(priority, high),
|
process_flag(priority, high),
|
||||||
erlang:system_monitor(self(), [{large_heap, LH}]),
|
erlang:system_monitor(self(), [{large_heap, LH}]),
|
||||||
lists:foreach(fun (Host) ->
|
lists:foreach(fun register_hook/1, ?MYHOSTS),
|
||||||
ejabberd_hooks:add(local_send_to_resource_hook, Host,
|
|
||||||
?MODULE, process_command, 50)
|
|
||||||
end,
|
|
||||||
?MYHOSTS),
|
|
||||||
{ok, #state{}}.
|
{ok, #state{}}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
@ -245,8 +245,9 @@ s2s_out_info(Pid) ->
|
|||||||
[<<"Process type: s2s_out">>,
|
[<<"Process type: s2s_out">>,
|
||||||
case FromTo of
|
case FromTo of
|
||||||
[{From, To}] ->
|
[{From, To}] ->
|
||||||
list_to_binary(io_lib:format("\nS2S connection: from ~s to ~s",
|
<<"\n",
|
||||||
[From, To]));
|
(io_lib:format("S2S connection: from ~s to ~s",
|
||||||
|
[From, To]))/binary>>;
|
||||||
_ -> <<"">>
|
_ -> <<"">>
|
||||||
end,
|
end,
|
||||||
check_send_queue(Pid), <<"\n">>,
|
check_send_queue(Pid), <<"\n">>,
|
||||||
@ -310,7 +311,7 @@ help() ->
|
|||||||
"<node>\n setlh <node> <integer>">>.
|
"<node>\n setlh <node> <integer>">>.
|
||||||
|
|
||||||
remote_command(Node, Args, From, To) ->
|
remote_command(Node, Args, From, To) ->
|
||||||
Message = case rpc:call(Node, ?MODULE,
|
Message = case ejabberd_cluster:call(Node, ?MODULE,
|
||||||
process_remote_command, [Args])
|
process_remote_command, [Args])
|
||||||
of
|
of
|
||||||
{badrpc, Reason} ->
|
{badrpc, Reason} ->
|
||||||
|
@ -67,9 +67,6 @@ update(ModulesToUpdate) ->
|
|||||||
{error, Reason}
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% OTP R14B03 and older provided release_handler_1:eval_script/3
|
|
||||||
%% But OTP R14B04 and newer provide release_handler_1:eval_script/5
|
|
||||||
%% Dialyzer reports a call to missing function; don't worry.
|
|
||||||
eval_script(Script, Apps, LibDirs) ->
|
eval_script(Script, Apps, LibDirs) ->
|
||||||
release_handler_1:eval_script(Script, Apps, LibDirs, [], []).
|
release_handler_1:eval_script(Script, Apps, LibDirs, [], []).
|
||||||
|
|
||||||
@ -138,17 +135,17 @@ build_script(Dir, UpdatedBeams) ->
|
|||||||
LowLevelScript,
|
LowLevelScript,
|
||||||
[{ejabberd, "", filename:join(Dir, "..")}]),
|
[{ejabberd, "", filename:join(Dir, "..")}]),
|
||||||
Check1 = case Check of
|
Check1 = case Check of
|
||||||
{ok, []} ->
|
{ok, []} ->
|
||||||
?DEBUG("script: ~p~n", [Script]),
|
?DEBUG("script: ~p~n", [Script]),
|
||||||
?DEBUG("low level script: ~p~n", [LowLevelScript]),
|
?DEBUG("low level script: ~p~n", [LowLevelScript]),
|
||||||
?DEBUG("check: ~p~n", [Check]),
|
?DEBUG("check: ~p~n", [Check]),
|
||||||
ok;
|
ok;
|
||||||
_ ->
|
_ ->
|
||||||
?ERROR_MSG("script: ~p~n", [Script]),
|
?ERROR_MSG("script: ~p~n", [Script]),
|
||||||
?ERROR_MSG("low level script: ~p~n", [LowLevelScript]),
|
?ERROR_MSG("low level script: ~p~n", [LowLevelScript]),
|
||||||
?ERROR_MSG("check: ~p~n", [Check]),
|
?ERROR_MSG("check: ~p~n", [Check]),
|
||||||
error
|
error
|
||||||
end,
|
end,
|
||||||
{Script, LowLevelScript, Check1}.
|
{Script, LowLevelScript, Check1}.
|
||||||
|
|
||||||
%% Copied from Erlang/OTP file: lib/sasl/src/systools.hrl
|
%% Copied from Erlang/OTP file: lib/sasl/src/systools.hrl
|
||||||
|
@ -1062,8 +1062,9 @@ term_to_string(T) ->
|
|||||||
|
|
||||||
%% @spec (T::any(), Cols::integer()) -> {NumLines::integer(), Paragraph::string()}
|
%% @spec (T::any(), Cols::integer()) -> {NumLines::integer(), Paragraph::string()}
|
||||||
term_to_paragraph(T, Cols) ->
|
term_to_paragraph(T, Cols) ->
|
||||||
Paragraph = list_to_binary(erl_prettypr:format(erl_syntax:abstract(T),
|
P1 = erl_syntax:abstract(T),
|
||||||
[{paper, Cols}])),
|
P2 = erl_prettypr:format(P1, [{paper, Cols}]),
|
||||||
|
Paragraph = list_to_binary(P2),
|
||||||
FieldList = ejabberd_regexp:split(Paragraph, <<"\n">>),
|
FieldList = ejabberd_regexp:split(Paragraph, <<"\n">>),
|
||||||
NumLines = length(FieldList),
|
NumLines = length(FieldList),
|
||||||
{NumLines, Paragraph}.
|
{NumLines, Paragraph}.
|
||||||
@ -1799,7 +1800,7 @@ get_node(Host, Node, [], _Query, Lang) ->
|
|||||||
<<"Modules">>)])]
|
<<"Modules">>)])]
|
||||||
++ MenuItems2))];
|
++ MenuItems2))];
|
||||||
get_node(global, Node, [<<"db">>], Query, Lang) ->
|
get_node(global, Node, [<<"db">>], Query, Lang) ->
|
||||||
case rpc:call(Node, mnesia, system_info, [tables]) of
|
case ejabberd_cluster:call(Node, mnesia, system_info, [tables]) of
|
||||||
{badrpc, _Reason} ->
|
{badrpc, _Reason} ->
|
||||||
[?XCT(<<"h1">>, <<"RPC Call Error">>)];
|
[?XCT(<<"h1">>, <<"RPC Call Error">>)];
|
||||||
Tables ->
|
Tables ->
|
||||||
@ -1811,7 +1812,7 @@ get_node(global, Node, [<<"db">>], Query, Lang) ->
|
|||||||
Rows = lists:map(fun (Table) ->
|
Rows = lists:map(fun (Table) ->
|
||||||
STable =
|
STable =
|
||||||
iolist_to_binary(atom_to_list(Table)),
|
iolist_to_binary(atom_to_list(Table)),
|
||||||
TInfo = case rpc:call(Node, mnesia,
|
TInfo = case ejabberd_cluster:call(Node, mnesia,
|
||||||
table_info,
|
table_info,
|
||||||
[Table, all])
|
[Table, all])
|
||||||
of
|
of
|
||||||
@ -2031,7 +2032,7 @@ get_node(global, Node, [<<"backup">>], Query, Lang) ->
|
|||||||
[?INPUTT(<<"submit">>, <<"import_dir">>,
|
[?INPUTT(<<"submit">>, <<"import_dir">>,
|
||||||
<<"OK">>)])])])])])];
|
<<"OK">>)])])])])])];
|
||||||
get_node(global, Node, [<<"ports">>], Query, Lang) ->
|
get_node(global, Node, [<<"ports">>], Query, Lang) ->
|
||||||
Ports = rpc:call(Node, ejabberd_config,
|
Ports = ejabberd_cluster:call(Node, ejabberd_config,
|
||||||
get_local_option, [listen,
|
get_local_option, [listen,
|
||||||
{ejabberd_listener, validate_cfg},
|
{ejabberd_listener, validate_cfg},
|
||||||
[]]),
|
[]]),
|
||||||
@ -2045,7 +2046,7 @@ get_node(global, Node, [<<"ports">>], Query, Lang) ->
|
|||||||
{error, iolist_to_binary(io_lib:format("~p", [Reason]))};
|
{error, iolist_to_binary(io_lib:format("~p", [Reason]))};
|
||||||
_ -> nothing
|
_ -> nothing
|
||||||
end,
|
end,
|
||||||
NewPorts = lists:sort(rpc:call(Node, ejabberd_config,
|
NewPorts = lists:sort(ejabberd_cluster:call(Node, ejabberd_config,
|
||||||
get_local_option,
|
get_local_option,
|
||||||
[listen,
|
[listen,
|
||||||
{ejabberd_listener, validate_cfg},
|
{ejabberd_listener, validate_cfg},
|
||||||
@ -2068,7 +2069,7 @@ get_node(global, Node, [<<"ports">>], Query, Lang) ->
|
|||||||
[node_ports_to_xhtml(NewPorts, Lang)])];
|
[node_ports_to_xhtml(NewPorts, Lang)])];
|
||||||
get_node(Host, Node, [<<"modules">>], Query, Lang)
|
get_node(Host, Node, [<<"modules">>], Query, Lang)
|
||||||
when is_binary(Host) ->
|
when is_binary(Host) ->
|
||||||
Modules = rpc:call(Node, gen_mod,
|
Modules = ejabberd_cluster:call(Node, gen_mod,
|
||||||
loaded_modules_with_opts, [Host]),
|
loaded_modules_with_opts, [Host]),
|
||||||
Res = case catch node_modules_parse_query(Host, Node,
|
Res = case catch node_modules_parse_query(Host, Node,
|
||||||
Modules, Query)
|
Modules, Query)
|
||||||
@ -2077,7 +2078,7 @@ get_node(Host, Node, [<<"modules">>], Query, Lang)
|
|||||||
{'EXIT', Reason} -> ?INFO_MSG("~p~n", [Reason]), error;
|
{'EXIT', Reason} -> ?INFO_MSG("~p~n", [Reason]), error;
|
||||||
_ -> nothing
|
_ -> nothing
|
||||||
end,
|
end,
|
||||||
NewModules = lists:sort(rpc:call(Node, gen_mod,
|
NewModules = lists:sort(ejabberd_cluster:call(Node, gen_mod,
|
||||||
loaded_modules_with_opts, [Host])),
|
loaded_modules_with_opts, [Host])),
|
||||||
H1String = list_to_binary(io_lib:format(?T(<<"Modules at ~p">>), [Node])),
|
H1String = list_to_binary(io_lib:format(?T(<<"Modules at ~p">>), [Node])),
|
||||||
(?H1GL(H1String, <<"modules-overview">>,
|
(?H1GL(H1String, <<"modules-overview">>,
|
||||||
@ -2093,21 +2094,21 @@ get_node(Host, Node, [<<"modules">>], Query, Lang)
|
|||||||
[{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}],
|
[{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}],
|
||||||
[node_modules_to_xhtml(NewModules, Lang)])];
|
[node_modules_to_xhtml(NewModules, Lang)])];
|
||||||
get_node(global, Node, [<<"stats">>], _Query, Lang) ->
|
get_node(global, Node, [<<"stats">>], _Query, Lang) ->
|
||||||
UpTime = rpc:call(Node, erlang, statistics,
|
UpTime = ejabberd_cluster:call(Node, erlang, statistics,
|
||||||
[wall_clock]),
|
[wall_clock]),
|
||||||
UpTimeS = list_to_binary(io_lib:format("~.3f",
|
UpTimeS = list_to_binary(io_lib:format("~.3f",
|
||||||
[element(1, UpTime) / 1000])),
|
[element(1, UpTime) / 1000])),
|
||||||
CPUTime = rpc:call(Node, erlang, statistics, [runtime]),
|
CPUTime = ejabberd_cluster:call(Node, erlang, statistics, [runtime]),
|
||||||
CPUTimeS = list_to_binary(io_lib:format("~.3f",
|
CPUTimeS = list_to_binary(io_lib:format("~.3f",
|
||||||
[element(1, CPUTime) / 1000])),
|
[element(1, CPUTime) / 1000])),
|
||||||
OnlineUsers = mnesia:table_info(session, size),
|
OnlineUsers = mnesia:table_info(session, size),
|
||||||
TransactionsCommitted = rpc:call(Node, mnesia,
|
TransactionsCommitted = ejabberd_cluster:call(Node, mnesia,
|
||||||
system_info, [transaction_commits]),
|
system_info, [transaction_commits]),
|
||||||
TransactionsAborted = rpc:call(Node, mnesia,
|
TransactionsAborted = ejabberd_cluster:call(Node, mnesia,
|
||||||
system_info, [transaction_failures]),
|
system_info, [transaction_failures]),
|
||||||
TransactionsRestarted = rpc:call(Node, mnesia,
|
TransactionsRestarted = ejabberd_cluster:call(Node, mnesia,
|
||||||
system_info, [transaction_restarts]),
|
system_info, [transaction_restarts]),
|
||||||
TransactionsLogged = rpc:call(Node, mnesia, system_info,
|
TransactionsLogged = ejabberd_cluster:call(Node, mnesia, system_info,
|
||||||
[transaction_log_writes]),
|
[transaction_log_writes]),
|
||||||
[?XC(<<"h1">>,
|
[?XC(<<"h1">>,
|
||||||
list_to_binary(io_lib:format(?T(<<"Statistics of ~p">>), [Node]))),
|
list_to_binary(io_lib:format(?T(<<"Statistics of ~p">>), [Node]))),
|
||||||
@ -2142,12 +2143,12 @@ get_node(global, Node, [<<"stats">>], _Query, Lang) ->
|
|||||||
?XAC(<<"td">>, [{<<"class">>, <<"alignright">>}],
|
?XAC(<<"td">>, [{<<"class">>, <<"alignright">>}],
|
||||||
(pretty_string_int(TransactionsLogged)))])])])];
|
(pretty_string_int(TransactionsLogged)))])])])];
|
||||||
get_node(global, Node, [<<"update">>], Query, Lang) ->
|
get_node(global, Node, [<<"update">>], Query, Lang) ->
|
||||||
rpc:call(Node, code, purge, [ejabberd_update]),
|
ejabberd_cluster:call(Node, code, purge, [ejabberd_update]),
|
||||||
Res = node_update_parse_query(Node, Query),
|
Res = node_update_parse_query(Node, Query),
|
||||||
rpc:call(Node, code, load_file, [ejabberd_update]),
|
ejabberd_cluster:call(Node, code, load_file, [ejabberd_update]),
|
||||||
{ok, _Dir, UpdatedBeams, Script, LowLevelScript,
|
{ok, _Dir, UpdatedBeams, Script, LowLevelScript,
|
||||||
Check} =
|
Check} =
|
||||||
rpc:call(Node, ejabberd_update, update_info, []),
|
ejabberd_cluster:call(Node, ejabberd_update, update_info, []),
|
||||||
Mods = case UpdatedBeams of
|
Mods = case UpdatedBeams of
|
||||||
[] -> ?CT(<<"None">>);
|
[] -> ?CT(<<"None">>);
|
||||||
_ ->
|
_ ->
|
||||||
@ -2216,14 +2217,14 @@ get_node(Host, Node, NPath, Query, Lang) ->
|
|||||||
node_parse_query(Node, Query) ->
|
node_parse_query(Node, Query) ->
|
||||||
case lists:keysearch(<<"restart">>, 1, Query) of
|
case lists:keysearch(<<"restart">>, 1, Query) of
|
||||||
{value, _} ->
|
{value, _} ->
|
||||||
case rpc:call(Node, init, restart, []) of
|
case ejabberd_cluster:call(Node, init, restart, []) of
|
||||||
{badrpc, _Reason} -> error;
|
{badrpc, _Reason} -> error;
|
||||||
_ -> ok
|
_ -> ok
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
case lists:keysearch(<<"stop">>, 1, Query) of
|
case lists:keysearch(<<"stop">>, 1, Query) of
|
||||||
{value, _} ->
|
{value, _} ->
|
||||||
case rpc:call(Node, init, stop, []) of
|
case ejabberd_cluster:call(Node, init, stop, []) of
|
||||||
{badrpc, _Reason} -> error;
|
{badrpc, _Reason} -> error;
|
||||||
_ -> ok
|
_ -> ok
|
||||||
end;
|
end;
|
||||||
@ -2307,35 +2308,35 @@ node_backup_parse_query(Node, Query) ->
|
|||||||
{value, {_, Path}} ->
|
{value, {_, Path}} ->
|
||||||
Res = case Action of
|
Res = case Action of
|
||||||
<<"store">> ->
|
<<"store">> ->
|
||||||
rpc:call(Node, mnesia, backup,
|
ejabberd_cluster:call(Node, mnesia, backup,
|
||||||
[binary_to_list(Path)]);
|
[binary_to_list(Path)]);
|
||||||
<<"restore">> ->
|
<<"restore">> ->
|
||||||
rpc:call(Node, ejabberd_admin,
|
ejabberd_cluster:call(Node, ejabberd_admin,
|
||||||
restore, [Path]);
|
restore, [Path]);
|
||||||
<<"fallback">> ->
|
<<"fallback">> ->
|
||||||
rpc:call(Node, mnesia,
|
ejabberd_cluster:call(Node, mnesia,
|
||||||
install_fallback,
|
install_fallback,
|
||||||
[binary_to_list(Path)]);
|
[binary_to_list(Path)]);
|
||||||
<<"dump">> ->
|
<<"dump">> ->
|
||||||
rpc:call(Node, ejabberd_admin,
|
ejabberd_cluster:call(Node, ejabberd_admin,
|
||||||
dump_to_textfile,
|
dump_to_textfile,
|
||||||
[Path]);
|
[Path]);
|
||||||
<<"load">> ->
|
<<"load">> ->
|
||||||
rpc:call(Node, mnesia,
|
ejabberd_cluster:call(Node, mnesia,
|
||||||
load_textfile,
|
load_textfile,
|
||||||
[binary_to_list(Path)]);
|
[binary_to_list(Path)]);
|
||||||
<<"import_piefxis_file">> ->
|
<<"import_piefxis_file">> ->
|
||||||
rpc:call(Node, ejabberd_piefxis,
|
ejabberd_cluster:call(Node, ejabberd_piefxis,
|
||||||
import_file, [Path]);
|
import_file, [Path]);
|
||||||
<<"export_piefxis_dir">> ->
|
<<"export_piefxis_dir">> ->
|
||||||
rpc:call(Node, ejabberd_piefxis,
|
ejabberd_cluster:call(Node, ejabberd_piefxis,
|
||||||
export_server, [Path]);
|
export_server, [Path]);
|
||||||
<<"export_piefxis_host_dir">> ->
|
<<"export_piefxis_host_dir">> ->
|
||||||
{value, {_, Host}} =
|
{value, {_, Host}} =
|
||||||
lists:keysearch(<<Action/binary,
|
lists:keysearch(<<Action/binary,
|
||||||
"host">>,
|
"host">>,
|
||||||
1, Query),
|
1, Query),
|
||||||
rpc:call(Node, ejabberd_piefxis,
|
ejabberd_cluster:call(Node, ejabberd_piefxis,
|
||||||
export_host,
|
export_host,
|
||||||
[Path, Host]);
|
[Path, Host]);
|
||||||
<<"export_sql_file">> ->
|
<<"export_sql_file">> ->
|
||||||
@ -2343,13 +2344,13 @@ node_backup_parse_query(Node, Query) ->
|
|||||||
lists:keysearch(<<Action/binary,
|
lists:keysearch(<<Action/binary,
|
||||||
"host">>,
|
"host">>,
|
||||||
1, Query),
|
1, Query),
|
||||||
rpc:call(Node, ejd2odbc,
|
ejabberd_cluster:call(Node, ejd2odbc,
|
||||||
export, [Host, Path]);
|
export, [Host, Path]);
|
||||||
<<"import_file">> ->
|
<<"import_file">> ->
|
||||||
rpc:call(Node, ejabberd_admin,
|
ejabberd_cluster:call(Node, ejabberd_admin,
|
||||||
import_file, [Path]);
|
import_file, [Path]);
|
||||||
<<"import_dir">> ->
|
<<"import_dir">> ->
|
||||||
rpc:call(Node, ejabberd_admin,
|
ejabberd_cluster:call(Node, ejabberd_admin,
|
||||||
import_dir, [Path])
|
import_dir, [Path])
|
||||||
end,
|
end,
|
||||||
case Res of
|
case Res of
|
||||||
@ -2474,10 +2475,10 @@ node_ports_parse_query(Node, Ports, Query) ->
|
|||||||
{ok, Tokens, _} =
|
{ok, Tokens, _} =
|
||||||
erl_scan:string(binary_to_list(SOpts) ++ "."),
|
erl_scan:string(binary_to_list(SOpts) ++ "."),
|
||||||
{ok, Opts} = erl_parse:parse_term(Tokens),
|
{ok, Opts} = erl_parse:parse_term(Tokens),
|
||||||
rpc:call(Node, ejabberd_listener,
|
ejabberd_cluster:call(Node, ejabberd_listener,
|
||||||
delete_listener,
|
delete_listener,
|
||||||
[PortIpNetp2, Module1]),
|
[PortIpNetp2, Module1]),
|
||||||
R = rpc:call(Node, ejabberd_listener,
|
R = ejabberd_cluster:call(Node, ejabberd_listener,
|
||||||
add_listener,
|
add_listener,
|
||||||
[PortIpNetp2, Module, Opts]),
|
[PortIpNetp2, Module, Opts]),
|
||||||
throw({is_added, R});
|
throw({is_added, R});
|
||||||
@ -2487,7 +2488,7 @@ node_ports_parse_query(Node, Ports, Query) ->
|
|||||||
1, Query)
|
1, Query)
|
||||||
of
|
of
|
||||||
{value, _} ->
|
{value, _} ->
|
||||||
rpc:call(Node, ejabberd_listener,
|
ejabberd_cluster:call(Node, ejabberd_listener,
|
||||||
delete_listener,
|
delete_listener,
|
||||||
[PortIpNetp, Module1]),
|
[PortIpNetp, Module1]),
|
||||||
throw(submitted);
|
throw(submitted);
|
||||||
@ -2520,7 +2521,7 @@ node_ports_parse_query(Node, Ports, Query) ->
|
|||||||
{Port2, _SPort, IP2, _SIP, _SSPort, NetProt2,
|
{Port2, _SPort, IP2, _SIP, _SSPort, NetProt2,
|
||||||
OptsClean} =
|
OptsClean} =
|
||||||
get_port_data({Port2, STIP2, NetProt2}, Opts),
|
get_port_data({Port2, STIP2, NetProt2}, Opts),
|
||||||
R = rpc:call(Node, ejabberd_listener, add_listener,
|
R = ejabberd_cluster:call(Node, ejabberd_listener, add_listener,
|
||||||
[{Port2, IP2, NetProt2}, Module, OptsClean]),
|
[{Port2, IP2, NetProt2}, Module, OptsClean]),
|
||||||
throw({is_added, R});
|
throw({is_added, R});
|
||||||
_ -> ok
|
_ -> ok
|
||||||
@ -2579,9 +2580,9 @@ node_modules_parse_query(Host, Node, Modules, Query) ->
|
|||||||
{ok, Tokens, _} =
|
{ok, Tokens, _} =
|
||||||
erl_scan:string(binary_to_list(<<SOpts/binary, ".">>)),
|
erl_scan:string(binary_to_list(<<SOpts/binary, ".">>)),
|
||||||
{ok, Opts} = erl_parse:parse_term(Tokens),
|
{ok, Opts} = erl_parse:parse_term(Tokens),
|
||||||
rpc:call(Node, gen_mod, stop_module,
|
ejabberd_cluster:call(Node, gen_mod, stop_module,
|
||||||
[Host, Module]),
|
[Host, Module]),
|
||||||
rpc:call(Node, gen_mod, start_module,
|
ejabberd_cluster:call(Node, gen_mod, start_module,
|
||||||
[Host, Module, Opts]),
|
[Host, Module, Opts]),
|
||||||
throw(submitted);
|
throw(submitted);
|
||||||
_ ->
|
_ ->
|
||||||
@ -2589,7 +2590,7 @@ node_modules_parse_query(Host, Node, Modules, Query) ->
|
|||||||
1, Query)
|
1, Query)
|
||||||
of
|
of
|
||||||
{value, _} ->
|
{value, _} ->
|
||||||
rpc:call(Node, gen_mod, stop_module,
|
ejabberd_cluster:call(Node, gen_mod, stop_module,
|
||||||
[Host, Module]),
|
[Host, Module]),
|
||||||
throw(submitted);
|
throw(submitted);
|
||||||
_ -> ok
|
_ -> ok
|
||||||
@ -2605,7 +2606,7 @@ node_modules_parse_query(Host, Node, Modules, Query) ->
|
|||||||
Module = jlib:binary_to_atom(SModule),
|
Module = jlib:binary_to_atom(SModule),
|
||||||
{ok, Tokens, _} = erl_scan:string(binary_to_list(<<SOpts/binary, ".">>)),
|
{ok, Tokens, _} = erl_scan:string(binary_to_list(<<SOpts/binary, ".">>)),
|
||||||
{ok, Opts} = erl_parse:parse_term(Tokens),
|
{ok, Opts} = erl_parse:parse_term(Tokens),
|
||||||
rpc:call(Node, gen_mod, start_module,
|
ejabberd_cluster:call(Node, gen_mod, start_module,
|
||||||
[Host, Module, Opts]),
|
[Host, Module, Opts]),
|
||||||
throw(submitted);
|
throw(submitted);
|
||||||
_ -> ok
|
_ -> ok
|
||||||
@ -2618,7 +2619,7 @@ node_update_parse_query(Node, Query) ->
|
|||||||
proplists:get_all_values(<<"selected">>, Query),
|
proplists:get_all_values(<<"selected">>, Query),
|
||||||
ModulesToUpdate = [jlib:binary_to_atom(M)
|
ModulesToUpdate = [jlib:binary_to_atom(M)
|
||||||
|| M <- ModulesToUpdateStrings],
|
|| M <- ModulesToUpdateStrings],
|
||||||
case rpc:call(Node, ejabberd_update, update,
|
case ejabberd_cluster:call(Node, ejabberd_update, update,
|
||||||
[ModulesToUpdate])
|
[ModulesToUpdate])
|
||||||
of
|
of
|
||||||
{ok, _} -> ok;
|
{ok, _} -> ok;
|
||||||
@ -2893,7 +2894,8 @@ make_menu_item(item, 3, URI, Name, Lang) ->
|
|||||||
|
|
||||||
%%%==================================
|
%%%==================================
|
||||||
|
|
||||||
%%% vim: set foldmethod=marker foldmarker=%%%%,%%%=:
|
|
||||||
|
|
||||||
opt_type(access) -> fun (V) -> V end;
|
opt_type(access) -> fun (V) -> V end;
|
||||||
opt_type(_) -> [access].
|
opt_type(_) -> [access].
|
||||||
|
|
||||||
|
%%% vim: set foldmethod=marker foldmarker=%%%%,%%%=:
|
||||||
|
@ -629,27 +629,10 @@ init([Hosts, Port, Rootdn, Passwd, Opts]) ->
|
|||||||
id = 0, dict = dict:new(), req_q = queue:new()},
|
id = 0, dict = dict:new(), req_q = queue:new()},
|
||||||
0}.
|
0}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: StateName/2
|
|
||||||
%% Called when gen_fsm:send_event/2,3 is invoked (async)
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
connecting(timeout, S) ->
|
connecting(timeout, S) ->
|
||||||
{ok, NextState, NewS} = connect_bind(S),
|
{ok, NextState, NewS} = connect_bind(S),
|
||||||
{next_state, NextState, NewS}.
|
{next_state, NextState, NewS}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: StateName/3
|
|
||||||
%% Called when gen_fsm:sync_send_event/2,3 is invoked.
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {reply, Reply, NextStateName, NextStateData} |
|
|
||||||
%% {reply, Reply, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData} |
|
|
||||||
%% {stop, Reason, Reply, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
connecting(Event, From, S) ->
|
connecting(Event, From, S) ->
|
||||||
Q = queue:in({Event, From}, S#eldap.req_q),
|
Q = queue:in({Event, From}, S#eldap.req_q),
|
||||||
{next_state, connecting, S#eldap{req_q = Q}}.
|
{next_state, connecting, S#eldap{req_q = Q}}.
|
||||||
@ -678,34 +661,15 @@ handle_event(close, _StateName, S) ->
|
|||||||
handle_event(_Event, StateName, S) ->
|
handle_event(_Event, StateName, S) ->
|
||||||
{next_state, StateName, S}.
|
{next_state, StateName, S}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_sync_event/4
|
|
||||||
%% Called when gen_fsm:sync_send_all_state_event/2,3 is invoked
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {reply, Reply, NextStateName, NextStateData} |
|
|
||||||
%% {reply, Reply, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData} |
|
|
||||||
%% {stop, Reason, Reply, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
handle_sync_event(_Event, _From, StateName, S) ->
|
handle_sync_event(_Event, _From, StateName, S) ->
|
||||||
{reply, {StateName, S}, StateName, S}.
|
{reply, {StateName, S}, StateName, S}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_info/3
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
%%
|
%%
|
||||||
%% Packets arriving in various states
|
%% Packets arriving in various states
|
||||||
%%
|
%%
|
||||||
handle_info({Tag, _Socket, Data}, connecting, S)
|
handle_info({Tag, _Socket, Data}, connecting, S)
|
||||||
when Tag == tcp; Tag == ssl ->
|
when Tag == tcp; Tag == ssl ->
|
||||||
?DEBUG("tcp packet received when disconnected!~n~p",
|
?DEBUG("tcp packet received when disconnected!~n~p", [Data]),
|
||||||
[Data]),
|
|
||||||
{next_state, connecting, S};
|
{next_state, connecting, S};
|
||||||
handle_info({Tag, _Socket, Data}, wait_bind_response, S)
|
handle_info({Tag, _Socket, Data}, wait_bind_response, S)
|
||||||
when Tag == tcp; Tag == ssl ->
|
when Tag == tcp; Tag == ssl ->
|
||||||
@ -724,8 +688,7 @@ handle_info({Tag, _Socket, Data}, wait_bind_response, S)
|
|||||||
{next_state, connecting, close_and_retry(S)}
|
{next_state, connecting, close_and_retry(S)}
|
||||||
end;
|
end;
|
||||||
handle_info({Tag, _Socket, Data}, StateName, S)
|
handle_info({Tag, _Socket, Data}, StateName, S)
|
||||||
when (StateName == active orelse
|
when (StateName == active orelse StateName == active_bind)
|
||||||
StateName == active_bind)
|
|
||||||
andalso (Tag == tcp orelse Tag == ssl) ->
|
andalso (Tag == tcp orelse Tag == ssl) ->
|
||||||
case catch recvd_packet(Data, S) of
|
case catch recvd_packet(Data, S) of
|
||||||
{response, Response, RequestType} ->
|
{response, Response, RequestType} ->
|
||||||
@ -766,8 +729,7 @@ handle_info({timeout, Timer, {cmd_timeout, Id}},
|
|||||||
handle_info({timeout, retry_connect}, connecting, S) ->
|
handle_info({timeout, retry_connect}, connecting, S) ->
|
||||||
{ok, NextState, NewS} = connect_bind(S),
|
{ok, NextState, NewS} = connect_bind(S),
|
||||||
{next_state, NextState, NewS};
|
{next_state, NextState, NewS};
|
||||||
handle_info({timeout, _Timer, bind_timeout},
|
handle_info({timeout, _Timer, bind_timeout}, wait_bind_response, S) ->
|
||||||
wait_bind_response, S) ->
|
|
||||||
{next_state, connecting, close_and_retry(S)};
|
{next_state, connecting, close_and_retry(S)};
|
||||||
%%
|
%%
|
||||||
%% Make sure we don't fill the message queue with rubbish
|
%% Make sure we don't fill the message queue with rubbish
|
||||||
@ -825,16 +787,14 @@ send_command(Command, From, S) ->
|
|||||||
Message = #'LDAPMessage'{messageID = Id,
|
Message = #'LDAPMessage'{messageID = Id,
|
||||||
protocolOp = {Name, Request}},
|
protocolOp = {Name, Request}},
|
||||||
?DEBUG("~p~n", [{Name, ejabberd_config:may_hide_data(Request)}]),
|
?DEBUG("~p~n", [{Name, ejabberd_config:may_hide_data(Request)}]),
|
||||||
{ok, Bytes} = 'ELDAPv3':encode('LDAPMessage',
|
{ok, Bytes} = 'ELDAPv3':encode('LDAPMessage', Message),
|
||||||
Message),
|
|
||||||
case (S#eldap.sockmod):send(S#eldap.fd, Bytes) of
|
case (S#eldap.sockmod):send(S#eldap.fd, Bytes) of
|
||||||
ok ->
|
ok ->
|
||||||
Timer = erlang:start_timer(?CMD_TIMEOUT, self(),
|
Timer = erlang:start_timer(?CMD_TIMEOUT, self(), {cmd_timeout, Id}),
|
||||||
{cmd_timeout, Id}),
|
New_dict = dict:store(Id, [{Timer, Command, From, Name}], S#eldap.dict),
|
||||||
New_dict = dict:store(Id,
|
{ok, S#eldap{id = Id, dict = New_dict}};
|
||||||
[{Timer, Command, From, Name}], S#eldap.dict),
|
Error ->
|
||||||
{ok, S#eldap{id = Id, dict = New_dict}};
|
Error
|
||||||
Error -> Error
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
gen_req({search, A}) ->
|
gen_req({search, A}) ->
|
||||||
@ -1148,8 +1108,7 @@ bind_request(Socket, S) ->
|
|||||||
Message = #'LDAPMessage'{messageID = Id,
|
Message = #'LDAPMessage'{messageID = Id,
|
||||||
protocolOp = {bindRequest, Req}},
|
protocolOp = {bindRequest, Req}},
|
||||||
?DEBUG("Bind Request Message:~p~n", [ejabberd_config:may_hide_data(Message)]),
|
?DEBUG("Bind Request Message:~p~n", [ejabberd_config:may_hide_data(Message)]),
|
||||||
{ok, Bytes} = 'ELDAPv3':encode('LDAPMessage',
|
{ok, Bytes} = 'ELDAPv3':encode('LDAPMessage', Message),
|
||||||
Message),
|
|
||||||
case (S#eldap.sockmod):send(Socket, Bytes) of
|
case (S#eldap.sockmod):send(Socket, Bytes) of
|
||||||
ok -> {ok, S#eldap{id = Id}};
|
ok -> {ok, S#eldap{id = Id}};
|
||||||
Error -> Error
|
Error -> Error
|
||||||
@ -1162,24 +1121,6 @@ next_host(Host,
|
|||||||
Hosts) -> % Find next in turn
|
Hosts) -> % Find next in turn
|
||||||
next_host(Host, Hosts, Hosts).
|
next_host(Host, Hosts, Hosts).
|
||||||
|
|
||||||
%%% --------------------------------------------------------------------
|
|
||||||
%%% Verify the input data
|
|
||||||
%%% --------------------------------------------------------------------
|
|
||||||
%%% --------------------------------------------------------------------
|
|
||||||
%%% Get and Validate the initial configuration
|
|
||||||
%%% --------------------------------------------------------------------
|
|
||||||
%% get_atom(Key, List) ->
|
|
||||||
%% case lists:keysearch(Key, 1, List) of
|
|
||||||
%% {value, {Key, Value}} when is_atom(Value) ->
|
|
||||||
%% Value;
|
|
||||||
%% {value, {Key, _Value}} ->
|
|
||||||
%% throw({error, "Bad Value in Config for " ++ atom_to_list(Key)});
|
|
||||||
%% false ->
|
|
||||||
%% throw({error, "No Entry in Config for " ++ atom_to_list(Key)})
|
|
||||||
%% end.
|
|
||||||
%%% --------------------------------------------------------------------
|
|
||||||
%%% Other Stuff
|
|
||||||
%%% --------------------------------------------------------------------
|
|
||||||
next_host(Host, [Host], Hosts) ->
|
next_host(Host, [Host], Hosts) ->
|
||||||
hd(Hosts); % Wrap back to first
|
hd(Hosts); % Wrap back to first
|
||||||
next_host(Host, [Host | Tail], _Hosts) ->
|
next_host(Host, [Host | Tail], _Hosts) ->
|
||||||
|
@ -44,9 +44,9 @@
|
|||||||
|
|
||||||
-record(state, {host, module, function}).
|
-record(state, {host, module, function}).
|
||||||
|
|
||||||
%%-type component() :: ejabberd_sm | ejabberd_local.
|
-type component() :: ejabberd_sm | ejabberd_local.
|
||||||
-type type() :: no_queue | one_queue | pos_integer() | parallel.
|
-type type() :: no_queue | one_queue | pos_integer() | parallel.
|
||||||
%%-type opts() :: no_queue | {one_queue, pid()} | {queues, [pid()]} | parallel.
|
-type opts() :: no_queue | {one_queue, pid()} | {queues, [pid()]} | parallel.
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% API
|
%% API
|
||||||
@ -62,33 +62,37 @@ start_link(Host, Module, Function) ->
|
|||||||
add_iq_handler(Component, Host, NS, Module, Function,
|
add_iq_handler(Component, Host, NS, Module, Function,
|
||||||
Type) ->
|
Type) ->
|
||||||
case Type of
|
case Type of
|
||||||
no_queue ->
|
no_queue ->
|
||||||
Component:register_iq_handler(Host, NS, Module,
|
Component:register_iq_handler(Host, NS, Module,
|
||||||
Function, no_queue);
|
Function, no_queue);
|
||||||
one_queue ->
|
one_queue ->
|
||||||
{ok, Pid} = supervisor:start_child(ejabberd_iq_sup,
|
{ok, Pid} = supervisor:start_child(ejabberd_iq_sup,
|
||||||
[Host, Module, Function]),
|
[Host, Module, Function]),
|
||||||
Component:register_iq_handler(Host, NS, Module,
|
Component:register_iq_handler(Host, NS, Module,
|
||||||
Function, {one_queue, Pid});
|
Function, {one_queue, Pid});
|
||||||
N when is_integer(N) ->
|
N when is_integer(N) ->
|
||||||
Pids = lists:map(fun (_) ->
|
Pids = lists:map(fun (_) ->
|
||||||
{ok, Pid} =
|
{ok, Pid} =
|
||||||
supervisor:start_child(ejabberd_iq_sup,
|
supervisor:start_child(ejabberd_iq_sup,
|
||||||
[Host, Module,
|
[Host, Module,
|
||||||
Function]),
|
Function]),
|
||||||
Pid
|
Pid
|
||||||
end,
|
end,
|
||||||
lists:seq(1, N)),
|
lists:seq(1, N)),
|
||||||
Component:register_iq_handler(Host, NS, Module,
|
Component:register_iq_handler(Host, NS, Module,
|
||||||
Function, {queues, Pids});
|
Function, {queues, Pids});
|
||||||
parallel ->
|
parallel ->
|
||||||
Component:register_iq_handler(Host, NS, Module,
|
Component:register_iq_handler(Host, NS, Module,
|
||||||
Function, parallel)
|
Function, parallel)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec remove_iq_handler(component(), binary(), binary()) -> any().
|
||||||
|
|
||||||
remove_iq_handler(Component, Host, NS) ->
|
remove_iq_handler(Component, Host, NS) ->
|
||||||
Component:unregister_iq_handler(Host, NS).
|
Component:unregister_iq_handler(Host, NS).
|
||||||
|
|
||||||
|
-spec stop_iq_handler(atom(), atom(), [pid()]) -> any().
|
||||||
|
|
||||||
stop_iq_handler(_Module, _Function, Opts) ->
|
stop_iq_handler(_Module, _Function, Opts) ->
|
||||||
case Opts of
|
case Opts of
|
||||||
{one_queue, Pid} -> gen_server:call(Pid, stop);
|
{one_queue, Pid} -> gen_server:call(Pid, stop);
|
||||||
@ -100,21 +104,25 @@ stop_iq_handler(_Module, _Function, Opts) ->
|
|||||||
_ -> ok
|
_ -> ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec handle(binary(), atom(), atom(), opts(), jid(), jid(), iq()) -> any().
|
||||||
|
|
||||||
handle(Host, Module, Function, Opts, From, To, IQ) ->
|
handle(Host, Module, Function, Opts, From, To, IQ) ->
|
||||||
case Opts of
|
case Opts of
|
||||||
no_queue ->
|
no_queue ->
|
||||||
process_iq(Host, Module, Function, From, To, IQ);
|
process_iq(Host, Module, Function, From, To, IQ);
|
||||||
{one_queue, Pid} -> Pid ! {process_iq, From, To, IQ};
|
{one_queue, Pid} ->
|
||||||
{queues, Pids} ->
|
Pid ! {process_iq, From, To, IQ};
|
||||||
Pid = lists:nth(erlang:phash(now(), length(Pids)),
|
{queues, Pids} ->
|
||||||
Pids),
|
Pid = lists:nth(erlang:phash(now(), length(Pids)), Pids),
|
||||||
Pid ! {process_iq, From, To, IQ};
|
Pid ! {process_iq, From, To, IQ};
|
||||||
parallel ->
|
parallel ->
|
||||||
spawn(?MODULE, process_iq,
|
spawn(?MODULE, process_iq,
|
||||||
[Host, Module, Function, From, To, IQ]);
|
[Host, Module, Function, From, To, IQ]);
|
||||||
_ -> todo
|
_ -> todo
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec process_iq(binary(), atom(), atom(), jid(), jid(), iq()) -> any().
|
||||||
|
|
||||||
process_iq(_Host, Module, Function, From, To, IQ) ->
|
process_iq(_Host, Module, Function, From, To, IQ) ->
|
||||||
case catch Module:Function(From, To, IQ) of
|
case catch Module:Function(From, To, IQ) of
|
||||||
{'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]);
|
{'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]);
|
||||||
@ -146,44 +154,16 @@ transform_module_options(Opts) ->
|
|||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: init(Args) -> {ok, State} |
|
|
||||||
%% {ok, State, Timeout} |
|
|
||||||
%% ignore |
|
|
||||||
%% {stop, Reason}
|
|
||||||
%% Description: Initiates the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
init([Host, Module, Function]) ->
|
init([Host, Module, Function]) ->
|
||||||
{ok,
|
{ok,
|
||||||
#state{host = Host, module = Module,
|
#state{host = Host, module = Module,
|
||||||
function = Function}}.
|
function = Function}}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
|
|
||||||
%% {reply, Reply, State, Timeout} |
|
|
||||||
%% {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, Reply, State} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling call messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_call(stop, _From, State) ->
|
handle_call(stop, _From, State) ->
|
||||||
Reply = ok, {stop, normal, Reply, State}.
|
Reply = ok, {stop, normal, Reply, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_cast(Msg, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_cast(_Msg, State) -> {noreply, State}.
|
handle_cast(_Msg, State) -> {noreply, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_info(Info, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling all non call/cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_info({process_iq, From, To, IQ},
|
handle_info({process_iq, From, To, IQ},
|
||||||
#state{host = Host, module = Module,
|
#state{host = Host, module = Module,
|
||||||
function = Function} =
|
function = Function} =
|
||||||
@ -192,19 +172,8 @@ handle_info({process_iq, From, To, IQ},
|
|||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_info(_Info, State) -> {noreply, State}.
|
handle_info(_Info, State) -> {noreply, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: terminate(Reason, State) -> void()
|
|
||||||
%% Description: This function is called by a gen_server when it is about to
|
|
||||||
%% terminate. It should be the opposite of Module:init/1 and do any necessary
|
|
||||||
%% cleaning up. When it returns, the gen_server terminates with Reason.
|
|
||||||
%% The return value is ignored.
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
terminate(_Reason, _State) -> ok.
|
terminate(_Reason, _State) -> ok.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
|
|
||||||
%% Description: Convert process state when code is changed
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
%%%
|
%%%
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
-module (mod_carboncopy).
|
-module (mod_carboncopy).
|
||||||
|
|
||||||
-author ('ecestari@process-one.net').
|
-author ('ecestari@process-one.net').
|
||||||
-protocol({xep, 280, '0.8'}).
|
-protocol({xep, 280, '0.8'}).
|
||||||
|
|
||||||
@ -112,7 +113,7 @@ iq_handler(From, _To, #iq{type=set, sub_el = #xmlel{name = Operation, children
|
|||||||
?INFO_MSG("carbons disabled for user ~s@~s/~s", [U,S,R]),
|
?INFO_MSG("carbons disabled for user ~s@~s/~s", [U,S,R]),
|
||||||
disable(S, U, R)
|
disable(S, U, R)
|
||||||
end,
|
end,
|
||||||
case Result of
|
case Result of
|
||||||
ok ->
|
ok ->
|
||||||
?DEBUG("carbons IQ result: ok", []),
|
?DEBUG("carbons IQ result: ok", []),
|
||||||
IQ#iq{type=result, sub_el=[]};
|
IQ#iq{type=result, sub_el=[]};
|
||||||
@ -129,9 +130,8 @@ user_send_packet(Packet, _C2SState, From, To) ->
|
|||||||
|
|
||||||
user_receive_packet(Packet, _C2SState, JID, _From, To) ->
|
user_receive_packet(Packet, _C2SState, JID, _From, To) ->
|
||||||
check_and_forward(JID, To, Packet, received).
|
check_and_forward(JID, To, Packet, received).
|
||||||
|
|
||||||
% verifier si le trafic est local
|
% Modified from original version:
|
||||||
% Modified from original version:
|
|
||||||
% - registered to the user_send_packet hook, to be called only once even for multicast
|
% - registered to the user_send_packet hook, to be called only once even for multicast
|
||||||
% - do not support "private" message mode, and do not modify the original packet in any way
|
% - do not support "private" message mode, and do not modify the original packet in any way
|
||||||
% - we also replicate "read" notifications
|
% - we also replicate "read" notifications
|
||||||
@ -145,8 +145,8 @@ check_and_forward(JID, To, Packet, Direction)->
|
|||||||
send_copies(JID, To, Packet, Direction),
|
send_copies(JID, To, Packet, Direction),
|
||||||
Packet;
|
Packet;
|
||||||
true ->
|
true ->
|
||||||
%% stop the hook chain, we don't want mod_logdb to register
|
%% stop the hook chain, we don't want logging modules to duplicates
|
||||||
%% this message (duplicate)
|
%% this message
|
||||||
{stop, Packet}
|
{stop, Packet}
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
@ -156,7 +156,7 @@ check_and_forward(JID, To, Packet, Direction)->
|
|||||||
remove_connection(User, Server, Resource, _Status)->
|
remove_connection(User, Server, Resource, _Status)->
|
||||||
disable(Server, User, Resource),
|
disable(Server, User, Resource),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
|
||||||
%%% Internal
|
%%% Internal
|
||||||
%% Direction = received | sent <received xmlns='urn:xmpp:carbons:1'/>
|
%% Direction = received | sent <received xmlns='urn:xmpp:carbons:1'/>
|
||||||
@ -208,31 +208,31 @@ send_copies(JID, To, Packet, Direction)->
|
|||||||
ok.
|
ok.
|
||||||
|
|
||||||
build_forward_packet(JID, Packet, Sender, Dest, Direction, ?NS_CARBONS_2) ->
|
build_forward_packet(JID, Packet, Sender, Dest, Direction, ?NS_CARBONS_2) ->
|
||||||
#xmlel{name = <<"message">>,
|
#xmlel{name = <<"message">>,
|
||||||
attrs = [{<<"xmlns">>, <<"jabber:client">>},
|
attrs = [{<<"xmlns">>, <<"jabber:client">>},
|
||||||
{<<"type">>, message_type(Packet)},
|
{<<"type">>, message_type(Packet)},
|
||||||
{<<"from">>, jlib:jid_to_string(Sender)},
|
{<<"from">>, jlib:jid_to_string(Sender)},
|
||||||
{<<"to">>, jlib:jid_to_string(Dest)}],
|
{<<"to">>, jlib:jid_to_string(Dest)}],
|
||||||
children = [
|
children = [
|
||||||
#xmlel{name = list_to_binary(atom_to_list(Direction)),
|
#xmlel{name = list_to_binary(atom_to_list(Direction)),
|
||||||
attrs = [{<<"xmlns">>, ?NS_CARBONS_2}],
|
attrs = [{<<"xmlns">>, ?NS_CARBONS_2}],
|
||||||
children = [
|
children = [
|
||||||
#xmlel{name = <<"forwarded">>,
|
#xmlel{name = <<"forwarded">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_FORWARD}],
|
attrs = [{<<"xmlns">>, ?NS_FORWARD}],
|
||||||
children = [
|
children = [
|
||||||
complete_packet(JID, Packet, Direction)]}
|
complete_packet(JID, Packet, Direction)]}
|
||||||
]}
|
]}
|
||||||
]};
|
]};
|
||||||
build_forward_packet(JID, Packet, Sender, Dest, Direction, ?NS_CARBONS_1) ->
|
build_forward_packet(JID, Packet, Sender, Dest, Direction, ?NS_CARBONS_1) ->
|
||||||
#xmlel{name = <<"message">>,
|
#xmlel{name = <<"message">>,
|
||||||
attrs = [{<<"xmlns">>, <<"jabber:client">>},
|
attrs = [{<<"xmlns">>, <<"jabber:client">>},
|
||||||
{<<"type">>, message_type(Packet)},
|
{<<"type">>, message_type(Packet)},
|
||||||
{<<"from">>, jlib:jid_to_string(Sender)},
|
{<<"from">>, jlib:jid_to_string(Sender)},
|
||||||
{<<"to">>, jlib:jid_to_string(Dest)}],
|
{<<"to">>, jlib:jid_to_string(Dest)}],
|
||||||
children = [
|
children = [
|
||||||
#xmlel{name = list_to_binary(atom_to_list(Direction)),
|
#xmlel{name = list_to_binary(atom_to_list(Direction)),
|
||||||
attrs = [{<<"xmlns">>, ?NS_CARBONS_1}]},
|
attrs = [{<<"xmlns">>, ?NS_CARBONS_1}]},
|
||||||
#xmlel{name = <<"forwarded">>,
|
#xmlel{name = <<"forwarded">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_FORWARD}],
|
attrs = [{<<"xmlns">>, ?NS_FORWARD}],
|
||||||
children = [complete_packet(JID, Packet, Direction)]}
|
children = [complete_packet(JID, Packet, Direction)]}
|
||||||
]}.
|
]}.
|
||||||
@ -285,7 +285,7 @@ has_non_empty_body(Packet) ->
|
|||||||
xml:get_subtag_cdata(Packet, <<"body">>) =/= <<"">>.
|
xml:get_subtag_cdata(Packet, <<"body">>) =/= <<"">>.
|
||||||
|
|
||||||
%% list {resource, cc_version} with carbons enabled for given user and host
|
%% list {resource, cc_version} with carbons enabled for given user and host
|
||||||
list(User, Server)->
|
list(User, Server) ->
|
||||||
mnesia:dirty_select(?TABLE, [{#carboncopy{us = {User, Server}, resource = '$2', version = '$3'}, [], [{{'$2','$3'}}]}]).
|
mnesia:dirty_select(?TABLE, [{#carboncopy{us = {User, Server}, resource = '$2', version = '$3'}, [], [{{'$2','$3'}}]}]).
|
||||||
|
|
||||||
|
|
||||||
|
@ -985,7 +985,7 @@ get_form(_Host, [<<"running nodes">>, ENode, <<"DB">>],
|
|||||||
case search_running_node(ENode) of
|
case search_running_node(ENode) of
|
||||||
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
||||||
Node ->
|
Node ->
|
||||||
case rpc:call(Node, mnesia, system_info, [tables]) of
|
case ejabberd_cluster:call(Node, mnesia, system_info, [tables]) of
|
||||||
{badrpc, _Reason} ->
|
{badrpc, _Reason} ->
|
||||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||||
Tables ->
|
Tables ->
|
||||||
@ -1007,7 +1007,7 @@ get_form(_Host, [<<"running nodes">>, ENode, <<"DB">>],
|
|||||||
?T(Lang,
|
?T(Lang,
|
||||||
<<"Choose storage type of tables">>)}]}
|
<<"Choose storage type of tables">>)}]}
|
||||||
| lists:map(fun (Table) ->
|
| lists:map(fun (Table) ->
|
||||||
case rpc:call(Node, mnesia,
|
case ejabberd_cluster:call(Node, mnesia,
|
||||||
table_info,
|
table_info,
|
||||||
[Table,
|
[Table,
|
||||||
storage_type])
|
storage_type])
|
||||||
@ -1028,7 +1028,7 @@ get_form(Host,
|
|||||||
case search_running_node(ENode) of
|
case search_running_node(ENode) of
|
||||||
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
||||||
Node ->
|
Node ->
|
||||||
case rpc:call(Node, gen_mod, loaded_modules, [Host]) of
|
case ejabberd_cluster:call(Node, gen_mod, loaded_modules, [Host]) of
|
||||||
{badrpc, _Reason} ->
|
{badrpc, _Reason} ->
|
||||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||||
Modules ->
|
Modules ->
|
||||||
@ -1607,7 +1607,7 @@ set_form(_From, Host,
|
|||||||
case Vals of
|
case Vals of
|
||||||
[<<"1">>] ->
|
[<<"1">>] ->
|
||||||
Module = jlib:binary_to_atom(Var),
|
Module = jlib:binary_to_atom(Var),
|
||||||
rpc:call(Node, gen_mod, stop_module,
|
ejabberd_cluster:call(Node, gen_mod, stop_module,
|
||||||
[Host, Module]);
|
[Host, Module]);
|
||||||
_ -> ok
|
_ -> ok
|
||||||
end
|
end
|
||||||
@ -1634,7 +1634,7 @@ set_form(_From, Host,
|
|||||||
case erl_parse:parse_term(Tokens) of
|
case erl_parse:parse_term(Tokens) of
|
||||||
{ok, Modules} ->
|
{ok, Modules} ->
|
||||||
lists:foreach(fun ({Module, Args}) ->
|
lists:foreach(fun ({Module, Args}) ->
|
||||||
rpc:call(Node, gen_mod,
|
ejabberd_cluster:call(Node, gen_mod,
|
||||||
start_module,
|
start_module,
|
||||||
[Host, Module, Args])
|
[Host, Module, Args])
|
||||||
end,
|
end,
|
||||||
@ -1656,7 +1656,7 @@ set_form(_From, _Host,
|
|||||||
case lists:keysearch(<<"path">>, 1, XData) of
|
case lists:keysearch(<<"path">>, 1, XData) of
|
||||||
false -> {error, ?ERR_BAD_REQUEST};
|
false -> {error, ?ERR_BAD_REQUEST};
|
||||||
{value, {_, [String]}} ->
|
{value, {_, [String]}} ->
|
||||||
case rpc:call(Node, mnesia, backup, [String]) of
|
case ejabberd_cluster:call(Node, mnesia, backup, [String]) of
|
||||||
{badrpc, _Reason} ->
|
{badrpc, _Reason} ->
|
||||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||||
{error, _Reason} -> {error, ?ERR_INTERNAL_SERVER_ERROR};
|
{error, _Reason} -> {error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||||
@ -1675,7 +1675,7 @@ set_form(_From, _Host,
|
|||||||
case lists:keysearch(<<"path">>, 1, XData) of
|
case lists:keysearch(<<"path">>, 1, XData) of
|
||||||
false -> {error, ?ERR_BAD_REQUEST};
|
false -> {error, ?ERR_BAD_REQUEST};
|
||||||
{value, {_, [String]}} ->
|
{value, {_, [String]}} ->
|
||||||
case rpc:call(Node, ejabberd_admin, restore, [String])
|
case ejabberd_cluster:call(Node, ejabberd_admin, restore, [String])
|
||||||
of
|
of
|
||||||
{badrpc, _Reason} ->
|
{badrpc, _Reason} ->
|
||||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||||
@ -1695,7 +1695,7 @@ set_form(_From, _Host,
|
|||||||
case lists:keysearch(<<"path">>, 1, XData) of
|
case lists:keysearch(<<"path">>, 1, XData) of
|
||||||
false -> {error, ?ERR_BAD_REQUEST};
|
false -> {error, ?ERR_BAD_REQUEST};
|
||||||
{value, {_, [String]}} ->
|
{value, {_, [String]}} ->
|
||||||
case rpc:call(Node, ejabberd_admin, dump_to_textfile,
|
case ejabberd_cluster:call(Node, ejabberd_admin, dump_to_textfile,
|
||||||
[String])
|
[String])
|
||||||
of
|
of
|
||||||
{badrpc, _Reason} ->
|
{badrpc, _Reason} ->
|
||||||
@ -1715,7 +1715,7 @@ set_form(_From, _Host,
|
|||||||
case lists:keysearch(<<"path">>, 1, XData) of
|
case lists:keysearch(<<"path">>, 1, XData) of
|
||||||
false -> {error, ?ERR_BAD_REQUEST};
|
false -> {error, ?ERR_BAD_REQUEST};
|
||||||
{value, {_, [String]}} ->
|
{value, {_, [String]}} ->
|
||||||
rpc:call(Node, jd2ejd, import_file, [String]),
|
ejabberd_cluster:call(Node, jd2ejd, import_file, [String]),
|
||||||
{result, []};
|
{result, []};
|
||||||
_ -> {error, ?ERR_BAD_REQUEST}
|
_ -> {error, ?ERR_BAD_REQUEST}
|
||||||
end
|
end
|
||||||
@ -1729,7 +1729,7 @@ set_form(_From, _Host,
|
|||||||
case lists:keysearch(<<"path">>, 1, XData) of
|
case lists:keysearch(<<"path">>, 1, XData) of
|
||||||
false -> {error, ?ERR_BAD_REQUEST};
|
false -> {error, ?ERR_BAD_REQUEST};
|
||||||
{value, {_, [String]}} ->
|
{value, {_, [String]}} ->
|
||||||
rpc:call(Node, jd2ejd, import_dir, [String]),
|
ejabberd_cluster:call(Node, jd2ejd, import_dir, [String]),
|
||||||
{result, []};
|
{result, []};
|
||||||
_ -> {error, ?ERR_BAD_REQUEST}
|
_ -> {error, ?ERR_BAD_REQUEST}
|
||||||
end
|
end
|
||||||
@ -1912,7 +1912,6 @@ set_form(From, Host,
|
|||||||
Server)
|
Server)
|
||||||
of
|
of
|
||||||
[] ->
|
[] ->
|
||||||
%% _US = {User, Server},
|
|
||||||
case get_last_info(User, Server) of
|
case get_last_info(User, Server) of
|
||||||
not_found -> ?T(Lang, <<"Never">>);
|
not_found -> ?T(Lang, <<"Never">>);
|
||||||
{ok, Timestamp, _Status} ->
|
{ok, Timestamp, _Status} ->
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
|
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||||
%%% @copyright (C) 2014, Evgeny Khramtsov
|
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%%
|
%%%
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% Created : 15 Aug 2014 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
%%% Created : 15 Aug 2014 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2014-2015 ProcessOne
|
%%% ejabberd, Copyright (C) 2014-2015 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
|
@ -784,8 +784,6 @@ set_form(ServerHost, Host, From, [], _Lang, XData) ->
|
|||||||
set_form(_ServerHost, _Host, _, _, _Lang, _XData) ->
|
set_form(_ServerHost, _Host, _, _, _Lang, _XData) ->
|
||||||
{error, ?ERR_SERVICE_UNAVAILABLE}.
|
{error, ?ERR_SERVICE_UNAVAILABLE}.
|
||||||
|
|
||||||
%% Host = "irc.example.com"
|
|
||||||
%% ServerHost = "example.com"
|
|
||||||
get_connection_params(Host, From, IRCServer) ->
|
get_connection_params(Host, From, IRCServer) ->
|
||||||
[_ | HostTail] = str:tokens(Host, <<".">>),
|
[_ | HostTail] = str:tokens(Host, <<".">>),
|
||||||
ServerHost = str:join(HostTail, <<".">>),
|
ServerHost = str:join(HostTail, <<".">>),
|
||||||
|
532
src/mod_mam.erl
532
src/mod_mam.erl
@ -43,27 +43,27 @@
|
|||||||
-include("mod_muc_room.hrl").
|
-include("mod_muc_room.hrl").
|
||||||
|
|
||||||
-record(archive_msg,
|
-record(archive_msg,
|
||||||
{us = {<<"">>, <<"">>} :: {binary(), binary()} | '$2',
|
{us = {<<"">>, <<"">>} :: {binary(), binary()} | '$2',
|
||||||
id = <<>> :: binary() | '_',
|
id = <<>> :: binary() | '_',
|
||||||
timestamp = now() :: erlang:timestamp() | '_' | '$1',
|
timestamp = now() :: erlang:timestamp() | '_' | '$1',
|
||||||
peer = {<<"">>, <<"">>, <<"">>} :: ljid() | '_' | '$3',
|
peer = {<<"">>, <<"">>, <<"">>} :: ljid() | '_' | '$3',
|
||||||
bare_peer = {<<"">>, <<"">>, <<"">>} :: ljid() | '_' | '$3',
|
bare_peer = {<<"">>, <<"">>, <<"">>} :: ljid() | '_' | '$3',
|
||||||
packet = #xmlel{} :: xmlel() | '_',
|
packet = #xmlel{} :: xmlel() | '_',
|
||||||
nick = <<"">> :: binary(),
|
nick = <<"">> :: binary(),
|
||||||
type = chat :: chat | groupchat}).
|
type = chat :: chat | groupchat}).
|
||||||
|
|
||||||
-record(archive_prefs,
|
-record(archive_prefs,
|
||||||
{us = {<<"">>, <<"">>} :: {binary(), binary()},
|
{us = {<<"">>, <<"">>} :: {binary(), binary()},
|
||||||
default = never :: never | always | roster,
|
default = never :: never | always | roster,
|
||||||
always = [] :: [ljid()],
|
always = [] :: [ljid()],
|
||||||
never = [] :: [ljid()]}).
|
never = [] :: [ljid()]}).
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
start(Host, Opts) ->
|
start(Host, Opts) ->
|
||||||
IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1,
|
IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1,
|
||||||
one_queue),
|
one_queue),
|
||||||
DBType = gen_mod:db_type(Host, Opts),
|
DBType = gen_mod:db_type(Host, Opts),
|
||||||
init_db(DBType, Host),
|
init_db(DBType, Host),
|
||||||
init_cache(DBType, Opts),
|
init_cache(DBType, Opts),
|
||||||
@ -80,9 +80,9 @@ start(Host, Opts) ->
|
|||||||
gen_iq_handler:add_iq_handler(ejabberd_sm, Host,
|
gen_iq_handler:add_iq_handler(ejabberd_sm, Host,
|
||||||
?NS_MAM_1, ?MODULE, process_iq_v0_3, IQDisc),
|
?NS_MAM_1, ?MODULE, process_iq_v0_3, IQDisc),
|
||||||
ejabberd_hooks:add(user_receive_packet, Host, ?MODULE,
|
ejabberd_hooks:add(user_receive_packet, Host, ?MODULE,
|
||||||
user_receive_packet, 500),
|
user_receive_packet, 500),
|
||||||
ejabberd_hooks:add(user_send_packet, Host, ?MODULE,
|
ejabberd_hooks:add(user_send_packet, Host, ?MODULE,
|
||||||
user_send_packet, 500),
|
user_send_packet, 500),
|
||||||
ejabberd_hooks:add(muc_filter_message, Host, ?MODULE,
|
ejabberd_hooks:add(muc_filter_message, Host, ?MODULE,
|
||||||
muc_filter_message, 50),
|
muc_filter_message, 50),
|
||||||
ejabberd_hooks:add(muc_process_iq, Host, ?MODULE,
|
ejabberd_hooks:add(muc_process_iq, Host, ?MODULE,
|
||||||
@ -95,21 +95,21 @@ start(Host, Opts) ->
|
|||||||
|
|
||||||
init_db(mnesia, _Host) ->
|
init_db(mnesia, _Host) ->
|
||||||
mnesia:create_table(archive_msg,
|
mnesia:create_table(archive_msg,
|
||||||
[{disc_only_copies, [node()]},
|
[{disc_only_copies, [node()]},
|
||||||
{type, bag},
|
{type, bag},
|
||||||
{attributes, record_info(fields, archive_msg)}]),
|
{attributes, record_info(fields, archive_msg)}]),
|
||||||
mnesia:create_table(archive_prefs,
|
mnesia:create_table(archive_prefs,
|
||||||
[{disc_only_copies, [node()]},
|
[{disc_only_copies, [node()]},
|
||||||
{attributes, record_info(fields, archive_prefs)}]);
|
{attributes, record_info(fields, archive_prefs)}]);
|
||||||
init_db(_, _) ->
|
init_db(_, _) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
init_cache(_DBType, Opts) ->
|
init_cache(_DBType, Opts) ->
|
||||||
MaxSize = gen_mod:get_opt(cache_size, Opts,
|
MaxSize = gen_mod:get_opt(cache_size, Opts,
|
||||||
fun(I) when is_integer(I), I>0 -> I end,
|
fun(I) when is_integer(I), I>0 -> I end,
|
||||||
1000),
|
1000),
|
||||||
LifeTime = gen_mod:get_opt(cache_life_time, Opts,
|
LifeTime = gen_mod:get_opt(cache_life_time, Opts,
|
||||||
fun(I) when is_integer(I), I>0 -> I end,
|
fun(I) when is_integer(I), I>0 -> I end,
|
||||||
timer:hours(1) div 1000),
|
timer:hours(1) div 1000),
|
||||||
cache_tab:new(archive_prefs, [{max_size, MaxSize},
|
cache_tab:new(archive_prefs, [{max_size, MaxSize},
|
||||||
{life_time, LifeTime}]).
|
{life_time, LifeTime}]).
|
||||||
@ -144,9 +144,9 @@ remove_user(User, Server) ->
|
|||||||
remove_user(LUser, LServer, mnesia) ->
|
remove_user(LUser, LServer, mnesia) ->
|
||||||
US = {LUser, LServer},
|
US = {LUser, LServer},
|
||||||
F = fun () ->
|
F = fun () ->
|
||||||
mnesia:delete({archive_msg, US}),
|
mnesia:delete({archive_msg, US}),
|
||||||
mnesia:delete({archive_prefs, US})
|
mnesia:delete({archive_prefs, US})
|
||||||
end,
|
end,
|
||||||
mnesia:transaction(F);
|
mnesia:transaction(F);
|
||||||
remove_user(LUser, LServer, odbc) ->
|
remove_user(LUser, LServer, odbc) ->
|
||||||
SUser = ejabberd_odbc:escape(LUser),
|
SUser = ejabberd_odbc:escape(LUser),
|
||||||
@ -162,25 +162,25 @@ user_receive_packet(Pkt, C2SState, JID, Peer, To) ->
|
|||||||
LServer = JID#jid.lserver,
|
LServer = JID#jid.lserver,
|
||||||
IsBareCopy = is_bare_copy(JID, To),
|
IsBareCopy = is_bare_copy(JID, To),
|
||||||
case should_archive(Pkt) of
|
case should_archive(Pkt) of
|
||||||
true when not IsBareCopy ->
|
true when not IsBareCopy ->
|
||||||
NewPkt = strip_my_archived_tag(Pkt, LServer),
|
NewPkt = strip_my_archived_tag(Pkt, LServer),
|
||||||
case store_msg(C2SState, NewPkt, LUser, LServer, Peer, recv) of
|
case store_msg(C2SState, NewPkt, LUser, LServer, Peer, recv) of
|
||||||
{ok, ID} ->
|
{ok, ID} ->
|
||||||
Archived = #xmlel{name = <<"archived">>,
|
Archived = #xmlel{name = <<"archived">>,
|
||||||
attrs = [{<<"by">>, LServer},
|
attrs = [{<<"by">>, LServer},
|
||||||
{<<"xmlns">>, ?NS_MAM_TMP},
|
{<<"xmlns">>, ?NS_MAM_TMP},
|
||||||
{<<"id">>, ID}]},
|
{<<"id">>, ID}]},
|
||||||
StanzaID = #xmlel{name = <<"stanza-id">>,
|
StanzaID = #xmlel{name = <<"stanza-id">>,
|
||||||
attrs = [{<<"by">>, LServer},
|
attrs = [{<<"by">>, LServer},
|
||||||
{<<"xmlns">>, ?NS_SID_0},
|
{<<"xmlns">>, ?NS_SID_0},
|
||||||
{<<"id">>, ID}]},
|
{<<"id">>, ID}]},
|
||||||
NewEls = [Archived, StanzaID|NewPkt#xmlel.children],
|
NewEls = [Archived, StanzaID|NewPkt#xmlel.children],
|
||||||
NewPkt#xmlel{children = NewEls};
|
NewPkt#xmlel{children = NewEls};
|
||||||
_ ->
|
_ ->
|
||||||
NewPkt
|
NewPkt
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
Pkt
|
Pkt
|
||||||
end.
|
end.
|
||||||
|
|
||||||
user_send_packet(Pkt, C2SState, JID, Peer) ->
|
user_send_packet(Pkt, C2SState, JID, Peer) ->
|
||||||
@ -188,12 +188,12 @@ user_send_packet(Pkt, C2SState, JID, Peer) ->
|
|||||||
LServer = JID#jid.lserver,
|
LServer = JID#jid.lserver,
|
||||||
case should_archive(Pkt) of
|
case should_archive(Pkt) of
|
||||||
true ->
|
true ->
|
||||||
NewPkt = strip_my_archived_tag(Pkt, LServer),
|
NewPkt = strip_my_archived_tag(Pkt, LServer),
|
||||||
store_msg(C2SState, jlib:replace_from_to(JID, Peer, NewPkt),
|
store_msg(C2SState, jlib:replace_from_to(JID, Peer, NewPkt),
|
||||||
LUser, LServer, Peer, send),
|
LUser, LServer, Peer, send),
|
||||||
NewPkt;
|
NewPkt;
|
||||||
false ->
|
false ->
|
||||||
Pkt
|
Pkt
|
||||||
end.
|
end.
|
||||||
|
|
||||||
muc_filter_message(Pkt, #state{config = Config} = MUCState,
|
muc_filter_message(Pkt, #state{config = Config} = MUCState,
|
||||||
@ -218,23 +218,23 @@ muc_filter_message(Pkt, #state{config = Config} = MUCState,
|
|||||||
|
|
||||||
% Query archive v0.2
|
% Query archive v0.2
|
||||||
process_iq_v0_2(#jid{lserver = LServer} = From,
|
process_iq_v0_2(#jid{lserver = LServer} = From,
|
||||||
#jid{lserver = LServer} = To,
|
#jid{lserver = LServer} = To,
|
||||||
#iq{type = get, sub_el = #xmlel{name = <<"query">>} = SubEl} = IQ) ->
|
#iq{type = get, sub_el = #xmlel{name = <<"query">>} = SubEl} = IQ) ->
|
||||||
Fs = lists:flatmap(
|
Fs = lists:flatmap(
|
||||||
fun(#xmlel{name = <<"start">>} = El) ->
|
fun (#xmlel{name = <<"start">>} = El) ->
|
||||||
[{<<"start">>, [xml:get_tag_cdata(El)]}];
|
[{<<"start">>, [xml:get_tag_cdata(El)]}];
|
||||||
(#xmlel{name = <<"end">>} = El) ->
|
(#xmlel{name = <<"end">>} = El) ->
|
||||||
[{<<"end">>, [xml:get_tag_cdata(El)]}];
|
[{<<"end">>, [xml:get_tag_cdata(El)]}];
|
||||||
(#xmlel{name = <<"with">>} = El) ->
|
(#xmlel{name = <<"with">>} = El) ->
|
||||||
[{<<"with">>, [xml:get_tag_cdata(El)]}];
|
[{<<"with">>, [xml:get_tag_cdata(El)]}];
|
||||||
(#xmlel{name = <<"withroom">>} = El) ->
|
(#xmlel{name = <<"withroom">>} = El) ->
|
||||||
[{<<"withroom">>, [xml:get_tag_cdata(El)]}];
|
[{<<"withroom">>, [xml:get_tag_cdata(El)]}];
|
||||||
(#xmlel{name = <<"withtext">>} = El) ->
|
(#xmlel{name = <<"withtext">>} = El) ->
|
||||||
[{<<"withtext">>, [xml:get_tag_cdata(El)]}];
|
[{<<"withtext">>, [xml:get_tag_cdata(El)]}];
|
||||||
(#xmlel{name = <<"set">>}) ->
|
(#xmlel{name = <<"set">>}) ->
|
||||||
[{<<"set">>, SubEl}];
|
[{<<"set">>, SubEl}];
|
||||||
(_) ->
|
(_) ->
|
||||||
[]
|
[]
|
||||||
end, SubEl#xmlel.children),
|
end, SubEl#xmlel.children),
|
||||||
process_iq(LServer, From, To, IQ, SubEl, Fs, chat);
|
process_iq(LServer, From, To, IQ, SubEl, Fs, chat);
|
||||||
process_iq_v0_2(From, To, IQ) ->
|
process_iq_v0_2(From, To, IQ) ->
|
||||||
@ -242,8 +242,8 @@ process_iq_v0_2(From, To, IQ) ->
|
|||||||
|
|
||||||
% Query archive v0.3
|
% Query archive v0.3
|
||||||
process_iq_v0_3(#jid{lserver = LServer} = From,
|
process_iq_v0_3(#jid{lserver = LServer} = From,
|
||||||
#jid{lserver = LServer} = To,
|
#jid{lserver = LServer} = To,
|
||||||
#iq{type = set, sub_el = #xmlel{name = <<"query">>} = SubEl} = IQ) ->
|
#iq{type = set, sub_el = #xmlel{name = <<"query">>} = SubEl} = IQ) ->
|
||||||
process_iq(LServer, From, To, IQ, SubEl, get_xdata_fields(SubEl), chat);
|
process_iq(LServer, From, To, IQ, SubEl, get_xdata_fields(SubEl), chat);
|
||||||
process_iq_v0_3(From, To, IQ) ->
|
process_iq_v0_3(From, To, IQ) ->
|
||||||
process_iq(From, To, IQ).
|
process_iq(From, To, IQ).
|
||||||
@ -266,15 +266,15 @@ muc_process_iq(IQ, _MUCState, _From, _To) ->
|
|||||||
|
|
||||||
get_xdata_fields(SubEl) ->
|
get_xdata_fields(SubEl) ->
|
||||||
case {xml:get_subtag_with_xmlns(SubEl, <<"x">>, ?NS_XDATA),
|
case {xml:get_subtag_with_xmlns(SubEl, <<"x">>, ?NS_XDATA),
|
||||||
xml:get_subtag_with_xmlns(SubEl, <<"set">>, ?NS_RSM)} of
|
xml:get_subtag_with_xmlns(SubEl, <<"set">>, ?NS_RSM)} of
|
||||||
{#xmlel{} = XData, false} ->
|
{#xmlel{} = XData, false} ->
|
||||||
jlib:parse_xdata_submit(XData);
|
jlib:parse_xdata_submit(XData);
|
||||||
{#xmlel{} = XData, #xmlel{}} ->
|
{#xmlel{} = XData, #xmlel{}} ->
|
||||||
[{<<"set">>, SubEl} | jlib:parse_xdata_submit(XData)];
|
[{<<"set">>, SubEl} | jlib:parse_xdata_submit(XData)];
|
||||||
{false, #xmlel{}} ->
|
{false, #xmlel{}} ->
|
||||||
[{<<"set">>, SubEl}];
|
[{<<"set">>, SubEl}];
|
||||||
{false, false} ->
|
{false, false} ->
|
||||||
[]
|
[]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
@ -283,32 +283,32 @@ get_xdata_fields(SubEl) ->
|
|||||||
|
|
||||||
% Preference setting (both v0.2 & v0.3)
|
% Preference setting (both v0.2 & v0.3)
|
||||||
process_iq(#jid{luser = LUser, lserver = LServer},
|
process_iq(#jid{luser = LUser, lserver = LServer},
|
||||||
#jid{lserver = LServer},
|
#jid{lserver = LServer},
|
||||||
#iq{type = set, sub_el = #xmlel{name = <<"prefs">>} = SubEl} = IQ) ->
|
#iq{type = set, sub_el = #xmlel{name = <<"prefs">>} = SubEl} = IQ) ->
|
||||||
try {case xml:get_tag_attr_s(<<"default">>, SubEl) of
|
try {case xml:get_tag_attr_s(<<"default">>, SubEl) of
|
||||||
<<"always">> -> always;
|
<<"always">> -> always;
|
||||||
<<"never">> -> never;
|
<<"never">> -> never;
|
||||||
<<"roster">> -> roster
|
<<"roster">> -> roster
|
||||||
end,
|
end,
|
||||||
lists:foldl(
|
lists:foldl(
|
||||||
fun(#xmlel{name = <<"always">>, children = Els}, {A, N}) ->
|
fun(#xmlel{name = <<"always">>, children = Els}, {A, N}) ->
|
||||||
{get_jids(Els) ++ A, N};
|
{get_jids(Els) ++ A, N};
|
||||||
(#xmlel{name = <<"never">>, children = Els}, {A, N}) ->
|
(#xmlel{name = <<"never">>, children = Els}, {A, N}) ->
|
||||||
{A, get_jids(Els) ++ N};
|
{A, get_jids(Els) ++ N};
|
||||||
(_, {A, N}) ->
|
(_, {A, N}) ->
|
||||||
{A, N}
|
{A, N}
|
||||||
end, {[], []}, SubEl#xmlel.children)} of
|
end, {[], []}, SubEl#xmlel.children)} of
|
||||||
{Default, {Always, Never}} ->
|
{Default, {Always, Never}} ->
|
||||||
case write_prefs(LUser, LServer, LServer, Default,
|
case write_prefs(LUser, LServer, LServer, Default,
|
||||||
lists:usort(Always), lists:usort(Never)) of
|
lists:usort(Always), lists:usort(Never)) of
|
||||||
ok ->
|
ok ->
|
||||||
IQ#iq{type = result, sub_el = []};
|
IQ#iq{type = result, sub_el = []};
|
||||||
_Err ->
|
_Err ->
|
||||||
IQ#iq{type = error,
|
IQ#iq{type = error,
|
||||||
sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}
|
sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}
|
||||||
end
|
end
|
||||||
catch _:_ ->
|
catch _:_ ->
|
||||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]}
|
IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]}
|
||||||
end;
|
end;
|
||||||
process_iq(_, _, #iq{sub_el = SubEl} = IQ) ->
|
process_iq(_, _, #iq{sub_el = SubEl} = IQ) ->
|
||||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}.
|
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}.
|
||||||
@ -344,64 +344,64 @@ process_iq(LServer, From, To, IQ, SubEl, Fs, MsgType) ->
|
|||||||
|
|
||||||
should_archive(#xmlel{name = <<"message">>} = Pkt) ->
|
should_archive(#xmlel{name = <<"message">>} = Pkt) ->
|
||||||
case {xml:get_attr_s(<<"type">>, Pkt#xmlel.attrs),
|
case {xml:get_attr_s(<<"type">>, Pkt#xmlel.attrs),
|
||||||
xml:get_subtag_cdata(Pkt, <<"body">>)} of
|
xml:get_subtag_cdata(Pkt, <<"body">>)} of
|
||||||
{<<"error">>, _} ->
|
{<<"error">>, _} ->
|
||||||
false;
|
|
||||||
{<<"groupchat">>, _} ->
|
|
||||||
false;
|
false;
|
||||||
{_, <<>>} ->
|
{<<"groupchat">>, _} ->
|
||||||
%% Empty body
|
false;
|
||||||
false;
|
{_, <<>>} ->
|
||||||
_ ->
|
%% Empty body
|
||||||
true
|
false;
|
||||||
|
_ ->
|
||||||
|
true
|
||||||
end;
|
end;
|
||||||
should_archive(#xmlel{}) ->
|
should_archive(#xmlel{}) ->
|
||||||
false.
|
false.
|
||||||
|
|
||||||
strip_my_archived_tag(Pkt, LServer) ->
|
strip_my_archived_tag(Pkt, LServer) ->
|
||||||
NewEls = lists:filter(
|
NewEls = lists:filter(
|
||||||
fun(#xmlel{name = Tag, attrs = Attrs})
|
fun(#xmlel{name = Tag, attrs = Attrs})
|
||||||
when Tag == <<"archived">>; Tag == <<"stanza-id">> ->
|
when Tag == <<"archived">>; Tag == <<"stanza-id">> ->
|
||||||
case catch jlib:nameprep(
|
case catch jlib:nameprep(
|
||||||
xml:get_attr_s(
|
xml:get_attr_s(
|
||||||
<<"by">>, Attrs)) of
|
<<"by">>, Attrs)) of
|
||||||
LServer ->
|
LServer ->
|
||||||
false;
|
false;
|
||||||
_ ->
|
_ ->
|
||||||
true
|
true
|
||||||
end;
|
end;
|
||||||
(_) ->
|
(_) ->
|
||||||
true
|
true
|
||||||
end, Pkt#xmlel.children),
|
end, Pkt#xmlel.children),
|
||||||
Pkt#xmlel{children = NewEls}.
|
Pkt#xmlel{children = NewEls}.
|
||||||
|
|
||||||
should_archive_peer(C2SState,
|
should_archive_peer(C2SState,
|
||||||
#archive_prefs{default = Default,
|
#archive_prefs{default = Default,
|
||||||
always = Always,
|
always = Always,
|
||||||
never = Never},
|
never = Never},
|
||||||
Peer) ->
|
Peer) ->
|
||||||
LPeer = jlib:jid_tolower(Peer),
|
LPeer = jlib:jid_tolower(Peer),
|
||||||
case lists:member(LPeer, Always) of
|
case lists:member(LPeer, Always) of
|
||||||
true ->
|
true ->
|
||||||
true;
|
true;
|
||||||
false ->
|
false ->
|
||||||
case lists:member(LPeer, Never) of
|
case lists:member(LPeer, Never) of
|
||||||
true ->
|
true ->
|
||||||
false;
|
false;
|
||||||
false ->
|
false ->
|
||||||
case Default of
|
case Default of
|
||||||
always -> true;
|
always -> true;
|
||||||
never -> false;
|
never -> false;
|
||||||
roster ->
|
roster ->
|
||||||
case ejabberd_c2s:get_subscription(
|
case ejabberd_c2s:get_subscription(
|
||||||
LPeer, C2SState) of
|
LPeer, C2SState) of
|
||||||
both -> true;
|
both -> true;
|
||||||
from -> true;
|
from -> true;
|
||||||
to -> true;
|
to -> true;
|
||||||
_ -> false
|
_ -> false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
should_archive_muc(_MUCState, _Peer) ->
|
should_archive_muc(_MUCState, _Peer) ->
|
||||||
@ -411,12 +411,12 @@ should_archive_muc(_MUCState, _Peer) ->
|
|||||||
store_msg(C2SState, Pkt, LUser, LServer, Peer, Dir) ->
|
store_msg(C2SState, Pkt, LUser, LServer, Peer, Dir) ->
|
||||||
Prefs = get_prefs(LUser, LServer),
|
Prefs = get_prefs(LUser, LServer),
|
||||||
case should_archive_peer(C2SState, Prefs, Peer) of
|
case should_archive_peer(C2SState, Prefs, Peer) of
|
||||||
true ->
|
true ->
|
||||||
US = {LUser, LServer},
|
US = {LUser, LServer},
|
||||||
store(Pkt, LServer, US, chat, Peer, <<"">>, Dir,
|
store(Pkt, LServer, US, chat, Peer, <<"">>, Dir,
|
||||||
gen_mod:db_type(LServer, ?MODULE));
|
gen_mod:db_type(LServer, ?MODULE));
|
||||||
false ->
|
false ->
|
||||||
pass
|
pass
|
||||||
end.
|
end.
|
||||||
|
|
||||||
store_muc(MUCState, Pkt, RoomJID, Peer, Nick) ->
|
store_muc(MUCState, Pkt, RoomJID, Peer, Nick) ->
|
||||||
@ -436,17 +436,17 @@ store(Pkt, _, {LUser, LServer}, Type, Peer, Nick, _Dir, mnesia) ->
|
|||||||
ID = jlib:integer_to_binary(now_to_usec(TS)),
|
ID = jlib:integer_to_binary(now_to_usec(TS)),
|
||||||
case mnesia:dirty_write(
|
case mnesia:dirty_write(
|
||||||
#archive_msg{us = {LUser, LServer},
|
#archive_msg{us = {LUser, LServer},
|
||||||
id = ID,
|
id = ID,
|
||||||
timestamp = TS,
|
timestamp = TS,
|
||||||
peer = LPeer,
|
peer = LPeer,
|
||||||
bare_peer = {PUser, PServer, <<>>},
|
bare_peer = {PUser, PServer, <<>>},
|
||||||
type = Type,
|
type = Type,
|
||||||
nick = Nick,
|
nick = Nick,
|
||||||
packet = Pkt}) of
|
packet = Pkt}) of
|
||||||
ok ->
|
ok ->
|
||||||
{ok, ID};
|
{ok, ID};
|
||||||
Err ->
|
Err ->
|
||||||
Err
|
Err
|
||||||
end;
|
end;
|
||||||
store(Pkt, LServer, {LUser, LHost}, Type, Peer, Nick, _Dir, odbc) ->
|
store(Pkt, LServer, {LUser, LHost}, Type, Peer, Nick, _Dir, odbc) ->
|
||||||
TSinteger = now_to_usec(now()),
|
TSinteger = now_to_usec(now()),
|
||||||
@ -456,28 +456,28 @@ store(Pkt, LServer, {LUser, LHost}, Type, Peer, Nick, _Dir, odbc) ->
|
|||||||
groupchat -> jlib:jid_to_string({LUser, LHost, <<>>})
|
groupchat -> jlib:jid_to_string({LUser, LHost, <<>>})
|
||||||
end,
|
end,
|
||||||
BarePeer = jlib:jid_to_string(
|
BarePeer = jlib:jid_to_string(
|
||||||
jlib:jid_tolower(
|
jlib:jid_tolower(
|
||||||
jlib:jid_remove_resource(Peer))),
|
jlib:jid_remove_resource(Peer))),
|
||||||
LPeer = jlib:jid_to_string(
|
LPeer = jlib:jid_to_string(
|
||||||
jlib:jid_tolower(Peer)),
|
jlib:jid_tolower(Peer)),
|
||||||
XML = xml:element_to_binary(Pkt),
|
XML = xml:element_to_binary(Pkt),
|
||||||
Body = xml:get_subtag_cdata(Pkt, <<"body">>),
|
Body = xml:get_subtag_cdata(Pkt, <<"body">>),
|
||||||
case ejabberd_odbc:sql_query(
|
case ejabberd_odbc:sql_query(
|
||||||
LServer,
|
LServer,
|
||||||
[<<"insert into archive (username, timestamp, "
|
[<<"insert into archive (username, timestamp, "
|
||||||
"peer, bare_peer, xml, txt, kind, nick) values (">>,
|
"peer, bare_peer, xml, txt, kind, nick) values (">>,
|
||||||
<<"'">>, ejabberd_odbc:escape(SUser), <<"', ">>,
|
<<"'">>, ejabberd_odbc:escape(SUser), <<"', ">>,
|
||||||
<<"'">>, TS, <<"', ">>,
|
<<"'">>, TS, <<"', ">>,
|
||||||
<<"'">>, ejabberd_odbc:escape(LPeer), <<"', ">>,
|
<<"'">>, ejabberd_odbc:escape(LPeer), <<"', ">>,
|
||||||
<<"'">>, ejabberd_odbc:escape(BarePeer), <<"', ">>,
|
<<"'">>, ejabberd_odbc:escape(BarePeer), <<"', ">>,
|
||||||
<<"'">>, ejabberd_odbc:escape(XML), <<"', ">>,
|
<<"'">>, ejabberd_odbc:escape(XML), <<"', ">>,
|
||||||
<<"'">>, ejabberd_odbc:escape(Body), <<"', ">>,
|
<<"'">>, ejabberd_odbc:escape(Body), <<"', ">>,
|
||||||
<<"'">>, jlib:atom_to_binary(Type), <<"', ">>,
|
<<"'">>, jlib:atom_to_binary(Type), <<"', ">>,
|
||||||
<<"'">>, ejabberd_odbc:escape(Nick), <<"');">>]) of
|
<<"'">>, ejabberd_odbc:escape(Nick), <<"');">>]) of
|
||||||
{updated, _} ->
|
{updated, _} ->
|
||||||
{ok, ID};
|
{ok, ID};
|
||||||
Err ->
|
Err ->
|
||||||
Err
|
Err
|
||||||
end.
|
end.
|
||||||
|
|
||||||
write_prefs(LUser, LServer, Host, Default, Always, Never) ->
|
write_prefs(LUser, LServer, Host, Default, Always, Never) ->
|
||||||
@ -486,9 +486,9 @@ write_prefs(LUser, LServer, Host, Default, Always, Never) ->
|
|||||||
DB -> DB
|
DB -> DB
|
||||||
end,
|
end,
|
||||||
Prefs = #archive_prefs{us = {LUser, LServer},
|
Prefs = #archive_prefs{us = {LUser, LServer},
|
||||||
default = Default,
|
default = Default,
|
||||||
always = Always,
|
always = Always,
|
||||||
never = Never},
|
never = Never},
|
||||||
cache_tab:dirty_insert(
|
cache_tab:dirty_insert(
|
||||||
archive_prefs, {LUser, LServer}, Prefs,
|
archive_prefs, {LUser, LServer}, Prefs,
|
||||||
fun() -> write_prefs(LUser, LServer, Prefs, DBType) end).
|
fun() -> write_prefs(LUser, LServer, Prefs, DBType) end).
|
||||||
@ -496,21 +496,21 @@ write_prefs(LUser, LServer, Host, Default, Always, Never) ->
|
|||||||
write_prefs(_LUser, _LServer, Prefs, mnesia) ->
|
write_prefs(_LUser, _LServer, Prefs, mnesia) ->
|
||||||
mnesia:dirty_write(Prefs);
|
mnesia:dirty_write(Prefs);
|
||||||
write_prefs(LUser, _LServer, #archive_prefs{default = Default,
|
write_prefs(LUser, _LServer, #archive_prefs{default = Default,
|
||||||
never = Never,
|
never = Never,
|
||||||
always = Always},
|
always = Always},
|
||||||
{odbc, Host}) ->
|
{odbc, Host}) ->
|
||||||
SUser = ejabberd_odbc:escape(LUser),
|
SUser = ejabberd_odbc:escape(LUser),
|
||||||
SDefault = erlang:atom_to_binary(Default, utf8),
|
SDefault = erlang:atom_to_binary(Default, utf8),
|
||||||
SAlways = ejabberd_odbc:encode_term(Always),
|
SAlways = ejabberd_odbc:encode_term(Always),
|
||||||
SNever = ejabberd_odbc:encode_term(Never),
|
SNever = ejabberd_odbc:encode_term(Never),
|
||||||
case update(Host, <<"archive_prefs">>,
|
case update(Host, <<"archive_prefs">>,
|
||||||
[<<"username">>, <<"def">>, <<"always">>, <<"never">>],
|
[<<"username">>, <<"def">>, <<"always">>, <<"never">>],
|
||||||
[SUser, SDefault, SAlways, SNever],
|
[SUser, SDefault, SAlways, SNever],
|
||||||
[<<"username='">>, SUser, <<"'">>]) of
|
[<<"username='">>, SUser, <<"'">>]) of
|
||||||
{updated, _} ->
|
{updated, _} ->
|
||||||
ok;
|
ok;
|
||||||
Err ->
|
Err ->
|
||||||
Err
|
Err
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_prefs(LUser, LServer) ->
|
get_prefs(LUser, LServer) ->
|
||||||
@ -520,24 +520,24 @@ get_prefs(LUser, LServer) ->
|
|||||||
DBType)
|
DBType)
|
||||||
end),
|
end),
|
||||||
case Res of
|
case Res of
|
||||||
{ok, Prefs} ->
|
{ok, Prefs} ->
|
||||||
Prefs;
|
Prefs;
|
||||||
error ->
|
error ->
|
||||||
Default = gen_mod:get_module_opt(
|
Default = gen_mod:get_module_opt(
|
||||||
LServer, ?MODULE, default,
|
LServer, ?MODULE, default,
|
||||||
fun(always) -> always;
|
fun(always) -> always;
|
||||||
(never) -> never;
|
(never) -> never;
|
||||||
(roster) -> roster
|
(roster) -> roster
|
||||||
end, never),
|
end, never),
|
||||||
#archive_prefs{us = {LUser, LServer}, default = Default}
|
#archive_prefs{us = {LUser, LServer}, default = Default}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_prefs(LUser, LServer, mnesia) ->
|
get_prefs(LUser, LServer, mnesia) ->
|
||||||
case mnesia:dirty_read(archive_prefs, {LUser, LServer}) of
|
case mnesia:dirty_read(archive_prefs, {LUser, LServer}) of
|
||||||
[Prefs] ->
|
[Prefs] ->
|
||||||
{ok, Prefs};
|
{ok, Prefs};
|
||||||
_ ->
|
_ ->
|
||||||
error
|
error
|
||||||
end;
|
end;
|
||||||
get_prefs(LUser, LServer, odbc) ->
|
get_prefs(LUser, LServer, odbc) ->
|
||||||
case ejabberd_odbc:sql_query(
|
case ejabberd_odbc:sql_query(
|
||||||
@ -545,16 +545,16 @@ get_prefs(LUser, LServer, odbc) ->
|
|||||||
[<<"select def, always, never from archive_prefs ">>,
|
[<<"select def, always, never from archive_prefs ">>,
|
||||||
<<"where username='">>,
|
<<"where username='">>,
|
||||||
ejabberd_odbc:escape(LUser), <<"';">>]) of
|
ejabberd_odbc:escape(LUser), <<"';">>]) of
|
||||||
{selected, _, [[SDefault, SAlways, SNever]]} ->
|
{selected, _, [[SDefault, SAlways, SNever]]} ->
|
||||||
Default = erlang:binary_to_existing_atom(SDefault, utf8),
|
Default = erlang:binary_to_existing_atom(SDefault, utf8),
|
||||||
Always = ejabberd_odbc:decode_term(SAlways),
|
Always = ejabberd_odbc:decode_term(SAlways),
|
||||||
Never = ejabberd_odbc:decode_term(SNever),
|
Never = ejabberd_odbc:decode_term(SNever),
|
||||||
{ok, #archive_prefs{us = {LUser, LServer},
|
{ok, #archive_prefs{us = {LUser, LServer},
|
||||||
default = Default,
|
default = Default,
|
||||||
always = Always,
|
always = Always,
|
||||||
never = Never}};
|
never = Never}};
|
||||||
_ ->
|
_ ->
|
||||||
error
|
error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
select_and_send(LServer, From, To, Start, End, With, RSM, IQ, MsgType) ->
|
select_and_send(LServer, From, To, Start, End, With, RSM, IQ, MsgType) ->
|
||||||
@ -578,7 +578,7 @@ select_and_start(LServer, From, To, Start, End, With, RSM, MsgType, DBType) ->
|
|||||||
{room, {_, _, <<"">>} = WithJID} ->
|
{room, {_, _, <<"">>} = WithJID} ->
|
||||||
select(LServer, jlib:make_jid(WithJID), Start, End,
|
select(LServer, jlib:make_jid(WithJID), Start, End,
|
||||||
WithJID, RSM, MsgType, DBType);
|
WithJID, RSM, MsgType, DBType);
|
||||||
_ ->
|
_ ->
|
||||||
select(LServer, From, Start, End,
|
select(LServer, From, Start, End,
|
||||||
With, RSM, MsgType, DBType)
|
With, RSM, MsgType, DBType)
|
||||||
end;
|
end;
|
||||||
@ -631,8 +631,8 @@ select(_LServer, #jid{luser = LUser, lserver = LServer} = JidRequestor,
|
|||||||
Count = length(Msgs),
|
Count = length(Msgs),
|
||||||
{lists:map(
|
{lists:map(
|
||||||
fun(Msg) ->
|
fun(Msg) ->
|
||||||
{Msg#archive_msg.id,
|
{Msg#archive_msg.id,
|
||||||
jlib:binary_to_integer(Msg#archive_msg.id),
|
jlib:binary_to_integer(Msg#archive_msg.id),
|
||||||
msg_to_el(Msg, MsgType, JidRequestor)}
|
msg_to_el(Msg, MsgType, JidRequestor)}
|
||||||
end, FilteredMsgs), IsComplete, Count};
|
end, FilteredMsgs), IsComplete, Count};
|
||||||
select(LServer, #jid{luser = LUser} = JidRequestor,
|
select(LServer, #jid{luser = LUser} = JidRequestor,
|
||||||
@ -650,8 +650,8 @@ select(LServer, #jid{luser = LUser} = JidRequestor,
|
|||||||
% the client did not specify a limit using RSM then the server
|
% the client did not specify a limit using RSM then the server
|
||||||
% should return a policy-violation error to the client.
|
% should return a policy-violation error to the client.
|
||||||
case {ejabberd_odbc:sql_query(Host, Query),
|
case {ejabberd_odbc:sql_query(Host, Query),
|
||||||
ejabberd_odbc:sql_query(Host, CountQuery)} of
|
ejabberd_odbc:sql_query(Host, CountQuery)} of
|
||||||
{{selected, _, Res}, {selected, _, [[Count]]}} ->
|
{{selected, _, Res}, {selected, _, [[Count]]}} ->
|
||||||
{Max, Direction} = case RSM of
|
{Max, Direction} = case RSM of
|
||||||
#rsm_in{max = M, direction = D} -> {M, D};
|
#rsm_in{max = M, direction = D} -> {M, D};
|
||||||
_ -> {undefined, undefined}
|
_ -> {undefined, undefined}
|
||||||
@ -666,24 +666,24 @@ select(LServer, #jid{luser = LUser} = JidRequestor,
|
|||||||
true ->
|
true ->
|
||||||
{Res, true}
|
{Res, true}
|
||||||
end,
|
end,
|
||||||
{lists:map(
|
{lists:map(
|
||||||
fun([TS, XML, PeerBin, Kind, Nick]) ->
|
fun([TS, XML, PeerBin, Kind, Nick]) ->
|
||||||
#xmlel{} = El = xml_stream:parse_element(XML),
|
#xmlel{} = El = xml_stream:parse_element(XML),
|
||||||
Now = usec_to_now(jlib:binary_to_integer(TS)),
|
Now = usec_to_now(jlib:binary_to_integer(TS)),
|
||||||
PeerJid = jlib:jid_tolower(jlib:string_to_jid(PeerBin)),
|
PeerJid = jlib:jid_tolower(jlib:string_to_jid(PeerBin)),
|
||||||
T = if Kind /= <<"">> ->
|
T = if Kind /= <<"">> ->
|
||||||
jlib:binary_to_atom(Kind);
|
jlib:binary_to_atom(Kind);
|
||||||
true -> chat
|
true -> chat
|
||||||
end,
|
end,
|
||||||
{TS, jlib:binary_to_integer(TS),
|
{TS, jlib:binary_to_integer(TS),
|
||||||
msg_to_el(#archive_msg{timestamp = Now,
|
msg_to_el(#archive_msg{timestamp = Now,
|
||||||
packet = El,
|
packet = El,
|
||||||
type = T,
|
type = T,
|
||||||
nick = Nick,
|
nick = Nick,
|
||||||
peer = PeerJid},
|
peer = PeerJid},
|
||||||
MsgType,
|
MsgType,
|
||||||
JidRequestor)}
|
JidRequestor)}
|
||||||
end, Res1), IsComplete, jlib:binary_to_integer(Count)};
|
end, Res1), IsComplete, jlib:binary_to_integer(Count)};
|
||||||
_ ->
|
_ ->
|
||||||
{[], false, 0}
|
{[], false, 0}
|
||||||
end.
|
end.
|
||||||
@ -693,12 +693,12 @@ msg_to_el(#archive_msg{timestamp = TS, packet = Pkt1, nick = Nick, peer = Peer},
|
|||||||
Delay = jlib:now_to_utc_string(TS),
|
Delay = jlib:now_to_utc_string(TS),
|
||||||
Pkt = maybe_update_from_to(Pkt1, JidRequestor, Peer, MsgType, Nick),
|
Pkt = maybe_update_from_to(Pkt1, JidRequestor, Peer, MsgType, Nick),
|
||||||
#xmlel{name = <<"forwarded">>,
|
#xmlel{name = <<"forwarded">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_FORWARD}],
|
attrs = [{<<"xmlns">>, ?NS_FORWARD}],
|
||||||
children = [#xmlel{name = <<"delay">>,
|
children = [#xmlel{name = <<"delay">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_DELAY},
|
attrs = [{<<"xmlns">>, ?NS_DELAY},
|
||||||
{<<"stamp">>, Delay}]},
|
{<<"stamp">>, Delay}]},
|
||||||
xml:replace_tag_attr(
|
xml:replace_tag_attr(
|
||||||
<<"xmlns">>, <<"jabber:client">>, Pkt)]}.
|
<<"xmlns">>, <<"jabber:client">>, Pkt)]}.
|
||||||
|
|
||||||
maybe_update_from_to(Pkt, JidRequestor, Peer, chat, _Nick) ->
|
maybe_update_from_to(Pkt, JidRequestor, Peer, chat, _Nick) ->
|
||||||
case xml:get_attr_s(<<"type">>, Pkt#xmlel.attrs) of
|
case xml:get_attr_s(<<"type">>, Pkt#xmlel.attrs) of
|
||||||
@ -864,42 +864,42 @@ match_rsm(_Now, _) ->
|
|||||||
make_matchspec(LUser, LServer, Start, End, {_, _, <<>>} = With) ->
|
make_matchspec(LUser, LServer, Start, End, {_, _, <<>>} = With) ->
|
||||||
ets:fun2ms(
|
ets:fun2ms(
|
||||||
fun(#archive_msg{timestamp = TS,
|
fun(#archive_msg{timestamp = TS,
|
||||||
us = US,
|
us = US,
|
||||||
bare_peer = BPeer} = Msg)
|
bare_peer = BPeer} = Msg)
|
||||||
when Start =< TS, End >= TS,
|
when Start =< TS, End >= TS,
|
||||||
US == {LUser, LServer},
|
US == {LUser, LServer},
|
||||||
BPeer == With ->
|
BPeer == With ->
|
||||||
Msg
|
Msg
|
||||||
end);
|
end);
|
||||||
make_matchspec(LUser, LServer, Start, End, {_, _, _} = With) ->
|
make_matchspec(LUser, LServer, Start, End, {_, _, _} = With) ->
|
||||||
ets:fun2ms(
|
ets:fun2ms(
|
||||||
fun(#archive_msg{timestamp = TS,
|
fun(#archive_msg{timestamp = TS,
|
||||||
us = US,
|
us = US,
|
||||||
peer = Peer} = Msg)
|
peer = Peer} = Msg)
|
||||||
when Start =< TS, End >= TS,
|
when Start =< TS, End >= TS,
|
||||||
US == {LUser, LServer},
|
US == {LUser, LServer},
|
||||||
Peer == With ->
|
Peer == With ->
|
||||||
Msg
|
Msg
|
||||||
end);
|
end);
|
||||||
make_matchspec(LUser, LServer, Start, End, none) ->
|
make_matchspec(LUser, LServer, Start, End, none) ->
|
||||||
ets:fun2ms(
|
ets:fun2ms(
|
||||||
fun(#archive_msg{timestamp = TS,
|
fun(#archive_msg{timestamp = TS,
|
||||||
us = US,
|
us = US,
|
||||||
peer = Peer} = Msg)
|
peer = Peer} = Msg)
|
||||||
when Start =< TS, End >= TS,
|
when Start =< TS, End >= TS,
|
||||||
US == {LUser, LServer} ->
|
US == {LUser, LServer} ->
|
||||||
Msg
|
Msg
|
||||||
end).
|
end).
|
||||||
|
|
||||||
make_sql_query(User, _LServer, Start, End, With, RSM) ->
|
make_sql_query(User, _LServer, Start, End, With, RSM) ->
|
||||||
{Max, Direction, ID} = case RSM of
|
{Max, Direction, ID} = case RSM of
|
||||||
#rsm_in{} ->
|
#rsm_in{} ->
|
||||||
{RSM#rsm_in.max,
|
{RSM#rsm_in.max,
|
||||||
RSM#rsm_in.direction,
|
RSM#rsm_in.direction,
|
||||||
RSM#rsm_in.id};
|
RSM#rsm_in.id};
|
||||||
none ->
|
none ->
|
||||||
{none, none, <<>>}
|
{none, none, <<>>}
|
||||||
end,
|
end,
|
||||||
LimitClause = if is_integer(Max), Max >= 0 ->
|
LimitClause = if is_integer(Max), Max >= 0 ->
|
||||||
[<<" limit ">>, jlib:integer_to_binary(Max+1)];
|
[<<" limit ">>, jlib:integer_to_binary(Max+1)];
|
||||||
true ->
|
true ->
|
||||||
@ -936,19 +936,19 @@ make_sql_query(User, _LServer, Start, End, With, RSM) ->
|
|||||||
[]
|
[]
|
||||||
end,
|
end,
|
||||||
StartClause = case Start of
|
StartClause = case Start of
|
||||||
{_, _, _} ->
|
{_, _, _} ->
|
||||||
[<<" and timestamp >= ">>,
|
[<<" and timestamp >= ">>,
|
||||||
jlib:integer_to_binary(now_to_usec(Start))];
|
jlib:integer_to_binary(now_to_usec(Start))];
|
||||||
_ ->
|
_ ->
|
||||||
[]
|
[]
|
||||||
end,
|
end,
|
||||||
EndClause = case End of
|
EndClause = case End of
|
||||||
{_, _, _} ->
|
{_, _, _} ->
|
||||||
[<<" and timestamp <= ">>,
|
[<<" and timestamp <= ">>,
|
||||||
jlib:integer_to_binary(now_to_usec(End))];
|
jlib:integer_to_binary(now_to_usec(End))];
|
||||||
_ ->
|
_ ->
|
||||||
[]
|
[]
|
||||||
end,
|
end,
|
||||||
SUser = ejabberd_odbc:escape(User),
|
SUser = ejabberd_odbc:escape(User),
|
||||||
|
|
||||||
Query = [<<"SELECT timestamp, xml, peer, kind, nick"
|
Query = [<<"SELECT timestamp, xml, peer, kind, nick"
|
||||||
@ -991,11 +991,11 @@ datetime_to_now(DateTime, USecs) ->
|
|||||||
get_jids(Els) ->
|
get_jids(Els) ->
|
||||||
lists:flatmap(
|
lists:flatmap(
|
||||||
fun(#xmlel{name = <<"jid">>} = El) ->
|
fun(#xmlel{name = <<"jid">>} = El) ->
|
||||||
J = jlib:string_to_jid(xml:get_tag_cdata(El)),
|
J = jlib:string_to_jid(xml:get_tag_cdata(El)),
|
||||||
[jlib:jid_tolower(jlib:jid_remove_resource(J)),
|
[jlib:jid_tolower(jlib:jid_remove_resource(J)),
|
||||||
jlib:jid_tolower(J)];
|
jlib:jid_tolower(J)];
|
||||||
(_) ->
|
(_) ->
|
||||||
[]
|
[]
|
||||||
end, Els).
|
end, Els).
|
||||||
|
|
||||||
update(LServer, Table, Fields, Vals, Where) ->
|
update(LServer, Table, Fields, Vals, Where) ->
|
||||||
|
183
src/mod_muc.erl
183
src/mod_muc.erl
@ -42,12 +42,12 @@
|
|||||||
restore_room/3,
|
restore_room/3,
|
||||||
forget_room/3,
|
forget_room/3,
|
||||||
create_room/5,
|
create_room/5,
|
||||||
shutdown_rooms/1,
|
shutdown_rooms/1,
|
||||||
process_iq_disco_items/4,
|
process_iq_disco_items/4,
|
||||||
broadcast_service_message/2,
|
broadcast_service_message/2,
|
||||||
export/1,
|
export/1,
|
||||||
import/1,
|
import/1,
|
||||||
import/3,
|
import/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,
|
||||||
@ -85,10 +85,6 @@
|
|||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% API
|
%% API
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
|
|
||||||
%% Description: Starts the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
start_link(Host, Opts) ->
|
start_link(Host, Opts) ->
|
||||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||||
gen_server:start_link({local, Proc}, ?MODULE,
|
gen_server:start_link({local, Proc}, ?MODULE,
|
||||||
@ -295,13 +291,6 @@ can_use_nick(LServer, Host, JID, Nick, odbc) ->
|
|||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: init(Args) -> {ok, State} |
|
|
||||||
%% {ok, State, Timeout} |
|
|
||||||
%% ignore |
|
|
||||||
%% {stop, Reason}
|
|
||||||
%% Description: Initiates the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
init([Host, Opts]) ->
|
init([Host, Opts]) ->
|
||||||
MyHost = gen_mod:get_opt_host(Host, Opts,
|
MyHost = gen_mod:get_opt_host(Host, Opts,
|
||||||
<<"conference.@HOST@">>),
|
<<"conference.@HOST@">>),
|
||||||
@ -390,8 +379,7 @@ init([Host, Opts]) ->
|
|||||||
ejabberd_router:register_route(MyHost),
|
ejabberd_router:register_route(MyHost),
|
||||||
load_permanent_rooms(MyHost, Host,
|
load_permanent_rooms(MyHost, Host,
|
||||||
{Access, AccessCreate, AccessAdmin, AccessPersistent},
|
{Access, AccessCreate, AccessAdmin, AccessPersistent},
|
||||||
HistorySize,
|
HistorySize, RoomShaper),
|
||||||
RoomShaper),
|
|
||||||
{ok, #state{host = MyHost,
|
{ok, #state{host = MyHost,
|
||||||
server_host = Host,
|
server_host = Host,
|
||||||
access = {Access, AccessCreate, AccessAdmin, AccessPersistent},
|
access = {Access, AccessCreate, AccessAdmin, AccessPersistent},
|
||||||
@ -399,15 +387,6 @@ init([Host, Opts]) ->
|
|||||||
history_size = HistorySize,
|
history_size = HistorySize,
|
||||||
room_shaper = RoomShaper}}.
|
room_shaper = RoomShaper}}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
|
|
||||||
%% {reply, Reply, State, Timeout} |
|
|
||||||
%% {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, Reply, State} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling call messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_call(stop, _From, State) ->
|
handle_call(stop, _From, State) ->
|
||||||
{stop, normal, ok, State};
|
{stop, normal, ok, State};
|
||||||
handle_call({create, Room, From, Nick, Opts}, _From,
|
handle_call({create, Room, From, Nick, Opts}, _From,
|
||||||
@ -428,20 +407,8 @@ handle_call({create, Room, From, Nick, Opts}, _From,
|
|||||||
register_room(Host, Room, Pid),
|
register_room(Host, Room, Pid),
|
||||||
{reply, ok, State}.
|
{reply, ok, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_cast(Msg, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_cast(_Msg, State) -> {noreply, State}.
|
handle_cast(_Msg, State) -> {noreply, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_info(Info, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling all non call/cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_info({route, From, To, Packet},
|
handle_info({route, From, To, Packet},
|
||||||
#state{host = Host, server_host = ServerHost,
|
#state{host = Host, server_host = ServerHost,
|
||||||
access = Access, default_room_opts = DefRoomOpts,
|
access = Access, default_room_opts = DefRoomOpts,
|
||||||
@ -468,21 +435,10 @@ handle_info({mnesia_system_event, {mnesia_down, Node}}, State) ->
|
|||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_info(_Info, State) -> {noreply, State}.
|
handle_info(_Info, State) -> {noreply, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: terminate(Reason, State) -> void()
|
|
||||||
%% Description: This function is called by a gen_server when it is about to
|
|
||||||
%% terminate. It should be the opposite of Module:init/1 and do any necessary
|
|
||||||
%% cleaning up. When it returns, the gen_server terminates with Reason.
|
|
||||||
%% The return value is ignored.
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
terminate(_Reason, State) ->
|
terminate(_Reason, State) ->
|
||||||
ejabberd_router:unregister_route(State#state.host),
|
ejabberd_router:unregister_route(State#state.host),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
|
|
||||||
%% Description: Convert process state when code is changed
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
@ -508,13 +464,13 @@ do_route(Host, ServerHost, Access, HistorySize, RoomShaper,
|
|||||||
case acl:match_rule(ServerHost, AccessRoute, From) of
|
case acl:match_rule(ServerHost, AccessRoute, From) of
|
||||||
allow ->
|
allow ->
|
||||||
do_route1(Host, ServerHost, Access, HistorySize, RoomShaper,
|
do_route1(Host, ServerHost, Access, HistorySize, RoomShaper,
|
||||||
From, To, Packet, DefRoomOpts);
|
From, To, Packet, DefRoomOpts);
|
||||||
_ ->
|
_ ->
|
||||||
#xmlel{attrs = Attrs} = Packet,
|
#xmlel{attrs = Attrs} = Packet,
|
||||||
Lang = xml:get_attr_s(<<"xml:lang">>, Attrs),
|
Lang = xml:get_attr_s(<<"xml:lang">>, Attrs),
|
||||||
ErrText = <<"Access denied by service policy">>,
|
ErrText = <<"Access denied by service policy">>,
|
||||||
Err = jlib:make_error_reply(Packet,
|
Err = jlib:make_error_reply(Packet,
|
||||||
?ERRT_FORBIDDEN(Lang, ErrText)),
|
?ERRT_FORBIDDEN(Lang, ErrText)),
|
||||||
ejabberd_router:route_error(To, From, Err, Packet)
|
ejabberd_router:route_error(To, From, Err, Packet)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
@ -645,26 +601,23 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper,
|
|||||||
<<"error">> -> ok;
|
<<"error">> -> ok;
|
||||||
<<"result">> -> ok;
|
<<"result">> -> ok;
|
||||||
_ ->
|
_ ->
|
||||||
Err = jlib:make_error_reply(
|
Err = jlib:make_error_reply(Packet,
|
||||||
Packet, ?ERR_ITEM_NOT_FOUND),
|
?ERR_ITEM_NOT_FOUND),
|
||||||
ejabberd_router:route(To, From, Err)
|
ejabberd_router:route(To, From, Err)
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
case mnesia:dirty_read(muc_online_room, {Room, Host}) of
|
case mnesia:dirty_read(muc_online_room, {Room, Host}) of
|
||||||
[] ->
|
[] ->
|
||||||
Type = xml:get_attr_s(<<"type">>, Attrs),
|
Type = xml:get_attr_s(<<"type">>, Attrs),
|
||||||
case {Name, Type} of
|
case {Name, Type} of
|
||||||
{<<"presence">>, <<"">>} ->
|
{<<"presence">>, <<"">>} ->
|
||||||
case check_user_can_create_room(ServerHost,
|
case check_user_can_create_room(ServerHost,
|
||||||
AccessCreate, From,
|
AccessCreate, From, Room) of
|
||||||
Room) of
|
|
||||||
true ->
|
true ->
|
||||||
{ok, Pid} = start_new_room(
|
{ok, Pid} = start_new_room(Host, ServerHost, Access,
|
||||||
Host, ServerHost, Access,
|
Room, HistorySize,
|
||||||
Room, HistorySize,
|
RoomShaper, From, Nick, DefRoomOpts),
|
||||||
RoomShaper, From,
|
|
||||||
Nick, DefRoomOpts),
|
|
||||||
register_room(Host, Room, Pid),
|
register_room(Host, Room, Pid),
|
||||||
mod_muc_room:route(Pid, From, Nick, Packet),
|
mod_muc_room:route(Pid, From, Nick, Packet),
|
||||||
ok;
|
ok;
|
||||||
@ -676,19 +629,18 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper,
|
|||||||
ejabberd_router:route(To, From, Err)
|
ejabberd_router:route(To, From, Err)
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
Lang = xml:get_attr_s(<<"xml:lang">>, Attrs),
|
Lang = xml:get_attr_s(<<"xml:lang">>, Attrs),
|
||||||
ErrText = <<"Conference room does not exist">>,
|
ErrText = <<"Conference room does not exist">>,
|
||||||
Err = jlib:make_error_reply(Packet,
|
Err = jlib:make_error_reply(Packet,
|
||||||
?ERRT_ITEM_NOT_FOUND(Lang,
|
?ERRT_ITEM_NOT_FOUND(Lang, ErrText)),
|
||||||
ErrText)),
|
ejabberd_router:route(To, From, Err)
|
||||||
ejabberd_router:route(To, From, Err)
|
end;
|
||||||
end;
|
[R] ->
|
||||||
[R] ->
|
Pid = R#muc_online_room.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
|
end
|
||||||
end
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
check_user_can_create_room(ServerHost, AccessCreate,
|
check_user_can_create_room(ServerHost, AccessCreate,
|
||||||
@ -743,48 +695,43 @@ get_rooms(LServer, Host, odbc) ->
|
|||||||
Err -> ?ERROR_MSG("failed to get rooms: ~p", [Err]), []
|
Err -> ?ERROR_MSG("failed to get rooms: ~p", [Err]), []
|
||||||
end.
|
end.
|
||||||
|
|
||||||
load_permanent_rooms(Host, ServerHost, Access, HistorySize, RoomShaper) ->
|
load_permanent_rooms(Host, ServerHost, Access,
|
||||||
|
HistorySize, RoomShaper) ->
|
||||||
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 mnesia:dirty_read(muc_online_room, {Room, Host}) of
|
||||||
[] ->
|
[] ->
|
||||||
{ok, Pid} = mod_muc_room:start(
|
{ok, Pid} = mod_muc_room:start(Host,
|
||||||
Host,
|
ServerHost, Access, Room,
|
||||||
ServerHost,
|
HistorySize, RoomShaper,
|
||||||
Access,
|
R#muc_room.opts),
|
||||||
Room,
|
register_room(Host, Room, Pid);
|
||||||
HistorySize,
|
_ -> ok
|
||||||
RoomShaper,
|
end
|
||||||
R#muc_room.opts),
|
end,
|
||||||
register_room(Host, Room, Pid);
|
get_rooms(ServerHost, Host)).
|
||||||
_ ->
|
|
||||||
ok
|
|
||||||
end
|
|
||||||
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,
|
||||||
Nick, DefRoomOpts) ->
|
Nick, DefRoomOpts) ->
|
||||||
case restore_room(ServerHost, Host, Room) of
|
case restore_room(ServerHost, Host, Room) of
|
||||||
error ->
|
error ->
|
||||||
?DEBUG("MUC: open new room '~s'~n", [Room]),
|
?DEBUG("MUC: open new room '~s'~n", [Room]),
|
||||||
mod_muc_room:start(Host, ServerHost, Access,
|
mod_muc_room:start(Host, ServerHost, Access, Room,
|
||||||
Room, HistorySize,
|
HistorySize, RoomShaper,
|
||||||
RoomShaper, From,
|
From, Nick, DefRoomOpts);
|
||||||
Nick, DefRoomOpts);
|
Opts ->
|
||||||
Opts ->
|
|
||||||
?DEBUG("MUC: restore room '~s'~n", [Room]),
|
?DEBUG("MUC: restore room '~s'~n", [Room]),
|
||||||
mod_muc_room:start(Host, ServerHost, Access,
|
mod_muc_room:start(Host, ServerHost, Access, Room,
|
||||||
Room, HistorySize,
|
HistorySize, RoomShaper, Opts)
|
||||||
RoomShaper, Opts)
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
register_room(Host, Room, Pid) ->
|
register_room(Host, Room, Pid) ->
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
mnesia:write(#muc_online_room{name_host = {Room, Host},
|
mnesia:write(#muc_online_room{name_host = {Room, Host},
|
||||||
pid = Pid})
|
pid = Pid})
|
||||||
end,
|
end,
|
||||||
mnesia:transaction(F).
|
mnesia:transaction(F).
|
||||||
|
|
||||||
|
|
||||||
@ -840,7 +787,6 @@ iq_disco_items(Host, From, Lang, none) ->
|
|||||||
_ -> false
|
_ -> false
|
||||||
end
|
end
|
||||||
end, get_vh_rooms(Host));
|
end, get_vh_rooms(Host));
|
||||||
|
|
||||||
iq_disco_items(Host, From, Lang, Rsm) ->
|
iq_disco_items(Host, From, Lang, Rsm) ->
|
||||||
{Rooms, RsmO} = get_vh_rooms(Host, Rsm),
|
{Rooms, RsmO} = get_vh_rooms(Host, Rsm),
|
||||||
RsmOut = jlib:rsm_encode(RsmO),
|
RsmOut = jlib:rsm_encode(RsmO),
|
||||||
@ -920,13 +866,6 @@ get_room_pos(Desired, [_ | Rooms], HeadPosition) ->
|
|||||||
flush() -> receive _ -> flush() after 0 -> ok end.
|
flush() -> receive _ -> flush() after 0 -> ok end.
|
||||||
|
|
||||||
-define(XFIELD(Type, Label, Var, Val),
|
-define(XFIELD(Type, Label, Var, Val),
|
||||||
%% @doc Get a pseudo unique Room Name. The Room Name is generated as a hash of
|
|
||||||
%% the requester JID, the local time and a random salt.
|
|
||||||
%%
|
|
||||||
%% "pseudo" because we don't verify that there is not a room
|
|
||||||
%% with the returned Name already created, nor mark the generated Name
|
|
||||||
%% as "already used". But in practice, it is unique enough. See
|
|
||||||
%% http://xmpp.org/extensions/xep-0045.html#createroom-unique
|
|
||||||
#xmlel{name = <<"field">>,
|
#xmlel{name = <<"field">>,
|
||||||
attrs =
|
attrs =
|
||||||
[{<<"type">>, Type},
|
[{<<"type">>, Type},
|
||||||
@ -1177,13 +1116,12 @@ iq_get_vcard(Lang) ->
|
|||||||
<<"ejabberd MUC module">>))/binary,
|
<<"ejabberd MUC module">>))/binary,
|
||||||
"\nCopyright (c) 2003-2015 ProcessOne">>}]}].
|
"\nCopyright (c) 2003-2015 ProcessOne">>}]}].
|
||||||
|
|
||||||
|
|
||||||
broadcast_service_message(Host, Msg) ->
|
broadcast_service_message(Host, Msg) ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun(#muc_online_room{pid = Pid}) ->
|
fun(#muc_online_room{pid = 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_vh_rooms(Host)).
|
||||||
|
|
||||||
|
|
||||||
get_vh_rooms(Host) ->
|
get_vh_rooms(Host) ->
|
||||||
@ -1349,8 +1287,7 @@ import(_LServer) ->
|
|||||||
[{<<"select name, host, opts from muc_room;">>,
|
[{<<"select name, host, opts from muc_room;">>,
|
||||||
fun([Name, RoomHost, SOpts]) ->
|
fun([Name, RoomHost, SOpts]) ->
|
||||||
Opts = opts_to_binary(ejabberd_odbc:decode_term(SOpts)),
|
Opts = opts_to_binary(ejabberd_odbc:decode_term(SOpts)),
|
||||||
#muc_room{name_host = {Name, RoomHost},
|
#muc_room{name_host = {Name, RoomHost}, opts = Opts}
|
||||||
opts = Opts}
|
|
||||||
end},
|
end},
|
||||||
{<<"select jid, host, nick from muc_registered;">>,
|
{<<"select jid, host, nick from muc_registered;">>,
|
||||||
fun([J, RoomHost, Nick]) ->
|
fun([J, RoomHost, Nick]) ->
|
||||||
|
@ -411,7 +411,6 @@ create_room(Name, Host, ServerHost) ->
|
|||||||
AcCreate = gen_mod:get_module_opt(ServerHost, mod_muc, access_create, fun(X) -> X end, all),
|
AcCreate = gen_mod:get_module_opt(ServerHost, mod_muc, access_create, fun(X) -> X end, all),
|
||||||
AcAdmin = gen_mod:get_module_opt(ServerHost, mod_muc, access_admin, fun(X) -> X end, none),
|
AcAdmin = gen_mod:get_module_opt(ServerHost, mod_muc, access_admin, fun(X) -> X end, none),
|
||||||
AcPer = gen_mod:get_module_opt(ServerHost, mod_muc, access_persistent, fun(X) -> X end, all),
|
AcPer = gen_mod:get_module_opt(ServerHost, mod_muc, access_persistent, fun(X) -> X end, all),
|
||||||
_PersistHistory = gen_mod:get_module_opt(ServerHost, mod_muc, persist_history, fun(X) -> X end, false),
|
|
||||||
HistorySize = gen_mod:get_module_opt(ServerHost, mod_muc, history_size, fun(X) -> X end, 20),
|
HistorySize = gen_mod:get_module_opt(ServerHost, mod_muc, history_size, fun(X) -> X end, 20),
|
||||||
RoomShaper = gen_mod:get_module_opt(ServerHost, mod_muc, room_shaper, fun(X) -> X end, none),
|
RoomShaper = gen_mod:get_module_opt(ServerHost, mod_muc, room_shaper, fun(X) -> X end, none),
|
||||||
|
|
||||||
|
@ -76,23 +76,14 @@
|
|||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% API
|
%% API
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
|
|
||||||
%% Description: Starts the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
start_link(Host, Opts) ->
|
start_link(Host, Opts) ->
|
||||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||||
gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
|
gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
|
||||||
|
|
||||||
start(Host, Opts) ->
|
start(Host, Opts) ->
|
||||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||||
ChildSpec =
|
ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]},
|
||||||
{Proc,
|
temporary, 1000, worker, [?MODULE]},
|
||||||
{?MODULE, start_link, [Host, Opts]},
|
|
||||||
temporary,
|
|
||||||
1000,
|
|
||||||
worker,
|
|
||||||
[?MODULE]},
|
|
||||||
supervisor:start_child(ejabberd_sup, ChildSpec).
|
supervisor:start_child(ejabberd_sup, ChildSpec).
|
||||||
|
|
||||||
stop(Host) ->
|
stop(Host) ->
|
||||||
@ -123,19 +114,11 @@ transform_module_options(Opts) ->
|
|||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: init(Args) -> {ok, State} |
|
|
||||||
%% {ok, State, Timeout} |
|
|
||||||
%% ignore |
|
|
||||||
%% {stop, Reason}
|
|
||||||
%% Description: Initiates the server
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
init([Host, Opts]) ->
|
init([Host, Opts]) ->
|
||||||
OutDir = gen_mod:get_opt(outdir, Opts,
|
OutDir = gen_mod:get_opt(outdir, Opts,
|
||||||
fun iolist_to_binary/1,
|
fun iolist_to_binary/1,
|
||||||
<<"www/muc">>),
|
<<"www/muc">>),
|
||||||
DirType = gen_mod:get_opt(dirtype, Opts,
|
DirType = gen_mod:get_opt(dirtype, Opts,
|
||||||
fun(subdirs) -> subdirs;
|
fun(subdirs) -> subdirs;
|
||||||
(plain) -> plain
|
(plain) -> plain
|
||||||
end, subdirs),
|
end, subdirs),
|
||||||
@ -181,31 +164,17 @@ init([Host, Opts]) ->
|
|||||||
{ok,
|
{ok,
|
||||||
#logstate{host = Host, out_dir = OutDir,
|
#logstate{host = Host, out_dir = OutDir,
|
||||||
dir_type = DirType, dir_name = DirName,
|
dir_type = DirType, dir_name = DirName,
|
||||||
file_format = FileFormat, file_permissions = FilePermissions, css_file = CSSFile,
|
file_format = FileFormat, css_file = CSSFile,
|
||||||
|
file_permissions = FilePermissions,
|
||||||
access = AccessLog, lang = Lang, timezone = Timezone,
|
access = AccessLog, lang = Lang, timezone = Timezone,
|
||||||
spam_prevention = NoFollow, top_link = Top_link}}.
|
spam_prevention = NoFollow, top_link = Top_link}}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
|
|
||||||
%% {reply, Reply, State, Timeout} |
|
|
||||||
%% {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, Reply, State} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling call messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_call({check_access_log, ServerHost, FromJID}, _From, State) ->
|
handle_call({check_access_log, ServerHost, FromJID}, _From, State) ->
|
||||||
Reply = acl:match_rule(ServerHost, State#logstate.access, FromJID),
|
Reply = acl:match_rule(ServerHost, State#logstate.access, FromJID),
|
||||||
{reply, Reply, State};
|
{reply, Reply, State};
|
||||||
handle_call(stop, _From, State) ->
|
handle_call(stop, _From, State) ->
|
||||||
{stop, normal, ok, State}.
|
{stop, normal, ok, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_cast(Msg, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_cast({add_to_log, Type, Data, Room, Opts}, State) ->
|
handle_cast({add_to_log, Type, Data, Room, Opts}, State) ->
|
||||||
case catch add_to_log2(Type, Data, Room, Opts, State) of
|
case catch add_to_log2(Type, Data, Room, Opts, State) of
|
||||||
{'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]);
|
{'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]);
|
||||||
@ -214,27 +183,10 @@ handle_cast({add_to_log, Type, Data, Room, Opts}, State) ->
|
|||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_cast(_Msg, State) -> {noreply, State}.
|
handle_cast(_Msg, State) -> {noreply, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: handle_info(Info, State) -> {noreply, State} |
|
|
||||||
%% {noreply, State, Timeout} |
|
|
||||||
%% {stop, Reason, State}
|
|
||||||
%% Description: Handling all non call/cast messages
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
handle_info(_Info, State) -> {noreply, State}.
|
handle_info(_Info, State) -> {noreply, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Function: terminate(Reason, State) -> void()
|
|
||||||
%% Description: This function is called by a gen_server when it is about to
|
|
||||||
%% terminate. It should be the opposite of Module:init/1 and do any necessary
|
|
||||||
%% cleaning up. When it returns, the gen_server terminates with Reason.
|
|
||||||
%% The return value is ignored.
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
terminate(_Reason, _State) -> ok.
|
terminate(_Reason, _State) -> ok.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
|
|
||||||
%% Description: Convert process state when code is changed
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
@ -242,19 +194,19 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
|||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
add_to_log2(text, {Nick, Packet}, Room, Opts, State) ->
|
add_to_log2(text, {Nick, Packet}, Room, Opts, State) ->
|
||||||
case has_no_permanent_store_hint(Packet) of
|
case has_no_permanent_store_hint(Packet) of
|
||||||
false ->
|
false ->
|
||||||
case {xml:get_subtag(Packet, <<"subject">>),
|
case {xml:get_subtag(Packet, <<"subject">>),
|
||||||
xml:get_subtag(Packet, <<"body">>)}
|
xml:get_subtag(Packet, <<"body">>)}
|
||||||
of
|
of
|
||||||
{false, false} -> ok;
|
{false, false} -> ok;
|
||||||
{false, SubEl} ->
|
{false, SubEl} ->
|
||||||
Message = {body, xml:get_tag_cdata(SubEl)},
|
Message = {body, xml:get_tag_cdata(SubEl)},
|
||||||
add_message_to_log(Nick, Message, Room, Opts, State);
|
add_message_to_log(Nick, Message, Room, Opts, State);
|
||||||
{SubEl, _} ->
|
{SubEl, _} ->
|
||||||
Message = {subject, xml:get_tag_cdata(SubEl)},
|
Message = {subject, xml:get_tag_cdata(SubEl)},
|
||||||
add_message_to_log(Nick, Message, Room, Opts, State)
|
add_message_to_log(Nick, Message, Room, Opts, State)
|
||||||
end;
|
end;
|
||||||
true -> ok
|
true -> ok
|
||||||
end;
|
end;
|
||||||
add_to_log2(roomconfig_change, _Occupants, Room, Opts,
|
add_to_log2(roomconfig_change, _Occupants, Room, Opts,
|
||||||
State) ->
|
State) ->
|
||||||
@ -349,7 +301,6 @@ close_previous_log(Fn, Images_dir, FileFormat) ->
|
|||||||
|
|
||||||
write_last_lines(_, _, plaintext) -> ok;
|
write_last_lines(_, _, plaintext) -> ok;
|
||||||
write_last_lines(F, Images_dir, _FileFormat) ->
|
write_last_lines(F, Images_dir, _FileFormat) ->
|
||||||
%% list_to_integer/2 was introduced in OTP R14
|
|
||||||
fw(F, <<"<div class=\"legend\">">>),
|
fw(F, <<"<div class=\"legend\">">>),
|
||||||
fw(F,
|
fw(F,
|
||||||
<<" <a href=\"http://www.ejabberd.im\"><img "
|
<<" <a href=\"http://www.ejabberd.im\"><img "
|
||||||
@ -378,7 +329,7 @@ write_last_lines(F, Images_dir, _FileFormat) ->
|
|||||||
fw(F, <<"</span></div></body></html>">>).
|
fw(F, <<"</span></div></body></html>">>).
|
||||||
|
|
||||||
set_filemode(Fn, {FileMode, FileGroup}) ->
|
set_filemode(Fn, {FileMode, FileGroup}) ->
|
||||||
ok = file:change_mode(Fn, list_to_integer(integer_to_list(FileMode), 8)),
|
ok = file:change_mode(Fn, list_to_integer(integer_to_list(FileMode), 8)),
|
||||||
ok = file:change_group(Fn, FileGroup).
|
ok = file:change_group(Fn, FileGroup).
|
||||||
|
|
||||||
htmlize_nick(Nick1, html) ->
|
htmlize_nick(Nick1, html) ->
|
||||||
@ -1163,10 +1114,7 @@ roomoccupants_to_string(Users, _FileFormat) ->
|
|||||||
Users1 /= []],
|
Users1 /= []],
|
||||||
iolist_to_binary([<<"<div class=\"rcot\">">>, Res, <<"</div>">>]).
|
iolist_to_binary([<<"<div class=\"rcot\">">>, Res, <<"</div>">>]).
|
||||||
|
|
||||||
%% Users = [{JID, Nick, Role}]
|
|
||||||
group_by_role(Users) ->
|
group_by_role(Users) ->
|
||||||
%% Role = atom()
|
|
||||||
%% Users = [{JID, Nick}]
|
|
||||||
{Ms, Ps, Vs, Ns} = lists:foldl(fun ({JID, Nick,
|
{Ms, Ps, Vs, Ns} = lists:foldl(fun ({JID, Nick,
|
||||||
moderator},
|
moderator},
|
||||||
{Mod, Par, Vis, Non}) ->
|
{Mod, Par, Vis, Non}) ->
|
||||||
@ -1238,7 +1186,8 @@ get_room_state(RoomPid) ->
|
|||||||
get_state),
|
get_state),
|
||||||
R.
|
R.
|
||||||
|
|
||||||
get_proc_name(Host) -> gen_mod:get_module_proc(Host, ?PROCNAME).
|
get_proc_name(Host) ->
|
||||||
|
gen_mod:get_module_proc(Host, ?PROCNAME).
|
||||||
|
|
||||||
calc_hour_offset(TimeHere) ->
|
calc_hour_offset(TimeHere) ->
|
||||||
TimeZero = calendar:now_to_universal_time(now()),
|
TimeZero = calendar:now_to_universal_time(now()),
|
||||||
|
@ -112,23 +112,17 @@ start_link(Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts) ->
|
|||||||
%%% Callback functions from gen_fsm
|
%%% Callback functions from gen_fsm
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
init([Host, ServerHost, Access, Room, HistorySize,
|
||||||
%% Func: init/1
|
RoomShaper, Creator, _Nick, DefRoomOpts]) ->
|
||||||
%% Returns: {ok, StateName, StateData} |
|
|
||||||
%% {ok, StateName, StateData, Timeout} |
|
|
||||||
%% ignore |
|
|
||||||
%% {stop, StopReason}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Creator, _Nick, DefRoomOpts]) ->
|
|
||||||
process_flag(trap_exit, true),
|
process_flag(trap_exit, true),
|
||||||
Shaper = shaper:new(RoomShaper),
|
Shaper = shaper:new(RoomShaper),
|
||||||
State = set_affiliation(Creator, owner,
|
State = set_affiliation(Creator, owner,
|
||||||
#state{host = Host, server_host = ServerHost,
|
#state{host = Host, server_host = ServerHost,
|
||||||
access = Access, room = Room,
|
access = Access, room = Room,
|
||||||
history = lqueue_new(HistorySize),
|
history = lqueue_new(HistorySize),
|
||||||
jid = jlib:make_jid(Room, Host, <<"">>),
|
jid = jlib:make_jid(Room, Host, <<"">>),
|
||||||
just_created = true,
|
just_created = true,
|
||||||
room_shaper = Shaper}),
|
room_shaper = Shaper}),
|
||||||
State1 = set_opts(DefRoomOpts, State),
|
State1 = set_opts(DefRoomOpts, State),
|
||||||
if (State1#state.config)#config.persistent ->
|
if (State1#state.config)#config.persistent ->
|
||||||
mod_muc:store_room(State1#state.server_host,
|
mod_muc:store_room(State1#state.server_host,
|
||||||
@ -137,7 +131,7 @@ init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Creator, _Nick, D
|
|||||||
make_opts(State1));
|
make_opts(State1));
|
||||||
true -> ok
|
true -> ok
|
||||||
end,
|
end,
|
||||||
?INFO_MSG("Created MUC room ~s@~s by ~s",
|
?INFO_MSG("Created MUC room ~s@~s by ~s",
|
||||||
[Room, Host, jlib:jid_to_string(Creator)]),
|
[Room, Host, jlib:jid_to_string(Creator)]),
|
||||||
add_to_log(room_existence, created, State1),
|
add_to_log(room_existence, created, State1),
|
||||||
add_to_log(room_existence, started, State1),
|
add_to_log(room_existence, started, State1),
|
||||||
@ -155,12 +149,6 @@ init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts]) ->
|
|||||||
add_to_log(room_existence, started, State),
|
add_to_log(room_existence, started, State),
|
||||||
{ok, normal_state, State}.
|
{ok, normal_state, State}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: StateName/2
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
normal_state({route, From, <<"">>,
|
normal_state({route, From, <<"">>,
|
||||||
#xmlel{name = <<"message">>, attrs = Attrs,
|
#xmlel{name = <<"message">>, attrs = Attrs,
|
||||||
children = Els} =
|
children = Els} =
|
||||||
@ -688,12 +676,6 @@ normal_state({route, From, ToNick,
|
|||||||
normal_state(_Event, StateData) ->
|
normal_state(_Event, StateData) ->
|
||||||
{next_state, normal_state, StateData}.
|
{next_state, normal_state, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_event/3
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
handle_event({service_message, Msg}, _StateName,
|
handle_event({service_message, Msg}, _StateName,
|
||||||
StateData) ->
|
StateData) ->
|
||||||
MessagePkt = #xmlel{name = <<"message">>,
|
MessagePkt = #xmlel{name = <<"message">>,
|
||||||
@ -742,15 +724,6 @@ handle_event({set_affiliations, Affiliations},
|
|||||||
handle_event(_Event, StateName, StateData) ->
|
handle_event(_Event, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData}.
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_sync_event/4
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {reply, Reply, NextStateName, NextStateData} |
|
|
||||||
%% {reply, Reply, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData} |
|
|
||||||
%% {stop, Reason, Reply, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
handle_sync_event({get_disco_item, JID, Lang}, _From, StateName, StateData) ->
|
handle_sync_event({get_disco_item, JID, Lang}, _From, StateName, StateData) ->
|
||||||
Reply = get_roomdesc_reply(JID, StateData,
|
Reply = get_roomdesc_reply(JID, StateData,
|
||||||
get_roomdesc_tail(StateData, Lang)),
|
get_roomdesc_tail(StateData, Lang)),
|
||||||
@ -779,12 +752,6 @@ handle_sync_event(_Event, _From, StateName,
|
|||||||
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
||||||
{ok, StateName, StateData}.
|
{ok, StateName, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: handle_info/3
|
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
||||||
%% {stop, Reason, NewStateData}
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
handle_info({process_user_presence, From}, normal_state = _StateName, StateData) ->
|
handle_info({process_user_presence, From}, normal_state = _StateName, StateData) ->
|
||||||
RoomQueueEmpty = queue:is_empty(StateData#state.room_queue),
|
RoomQueueEmpty = queue:is_empty(StateData#state.room_queue),
|
||||||
RoomQueue = queue:in({presence, From}, StateData#state.room_queue),
|
RoomQueue = queue:in({presence, From}, StateData#state.room_queue),
|
||||||
@ -864,11 +831,6 @@ handle_info(shutdown, _StateName, StateData) ->
|
|||||||
handle_info(_Info, StateName, StateData) ->
|
handle_info(_Info, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData}.
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
%% Func: terminate/3
|
|
||||||
%% Purpose: Shutdown the fsm
|
|
||||||
%% Returns: any
|
|
||||||
%%----------------------------------------------------------------------
|
|
||||||
terminate(Reason, _StateName, StateData) ->
|
terminate(Reason, _StateName, StateData) ->
|
||||||
?INFO_MSG("Stopping MUC room ~s@~s",
|
?INFO_MSG("Stopping MUC room ~s@~s",
|
||||||
[StateData#state.room, StateData#state.host]),
|
[StateData#state.room, StateData#state.host]),
|
||||||
@ -979,7 +941,7 @@ process_groupchat_message(From,
|
|||||||
StateData#state.server_host,
|
StateData#state.server_host,
|
||||||
StateData#state.users,
|
StateData#state.users,
|
||||||
NewPacket),
|
NewPacket),
|
||||||
NewStateData2 = case has_body_or_subject(Packet) of
|
NewStateData2 = case has_body_or_subject(NewPacket) of
|
||||||
true ->
|
true ->
|
||||||
add_message_to_history(FromNick, From,
|
add_message_to_history(FromNick, From,
|
||||||
NewPacket,
|
NewPacket,
|
||||||
@ -1808,9 +1770,9 @@ is_nick_change(JID, Nick, StateData) ->
|
|||||||
|
|
||||||
nick_collision(User, Nick, StateData) ->
|
nick_collision(User, Nick, StateData) ->
|
||||||
UserOfNick = find_jid_by_nick(Nick, StateData),
|
UserOfNick = find_jid_by_nick(Nick, StateData),
|
||||||
UserOfNick /= false andalso
|
(UserOfNick /= false andalso
|
||||||
jlib:jid_remove_resource(jlib:jid_tolower(UserOfNick))
|
jlib:jid_remove_resource(jlib:jid_tolower(UserOfNick))
|
||||||
/= jlib:jid_remove_resource(jlib:jid_tolower(User)).
|
/= jlib:jid_remove_resource(jlib:jid_tolower(User))).
|
||||||
|
|
||||||
add_new_user(From, Nick,
|
add_new_user(From, Nick,
|
||||||
#xmlel{attrs = Attrs, children = Els} = Packet,
|
#xmlel{attrs = Attrs, children = Els} = Packet,
|
||||||
@ -4412,7 +4374,6 @@ check_invitation(From, Els, Lang, StateData) ->
|
|||||||
jlib:jid_to_string({StateData#state.room,
|
jlib:jid_to_string({StateData#state.room,
|
||||||
StateData#state.host,
|
StateData#state.host,
|
||||||
<<"">>})]),
|
<<"">>})]),
|
||||||
|
|
||||||
case
|
case
|
||||||
(StateData#state.config)#config.password_protected
|
(StateData#state.config)#config.password_protected
|
||||||
of
|
of
|
||||||
@ -4561,6 +4522,13 @@ tab_count_user(JID) ->
|
|||||||
element_size(El) ->
|
element_size(El) ->
|
||||||
byte_size(xml:element_to_binary(El)).
|
byte_size(xml:element_to_binary(El)).
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% Multicast
|
||||||
|
|
||||||
|
send_multiple(From, Server, Users, Packet) ->
|
||||||
|
JIDs = [ User#user.jid || {_, User} <- ?DICT:to_list(Users)],
|
||||||
|
ejabberd_router_multicast:route_multicast(From, Server, JIDs, Packet).
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
%% Detect messange stanzas that don't have meaninful content
|
%% Detect messange stanzas that don't have meaninful content
|
||||||
|
|
||||||
@ -4571,9 +4539,3 @@ has_body_or_subject(Packet) ->
|
|||||||
(_) -> true
|
(_) -> true
|
||||||
end, Packet#xmlel.children).
|
end, Packet#xmlel.children).
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
%% Multicast
|
|
||||||
|
|
||||||
send_multiple(From, Server, Users, Packet) ->
|
|
||||||
JIDs = [ User#user.jid || {_, User} <- ?DICT:to_list(Users)],
|
|
||||||
ejabberd_router_multicast:route_multicast(From, Server, JIDs, Packet).
|
|
||||||
|
@ -3,6 +3,24 @@
|
|||||||
%%% Author : Badlop <badlop@process-one.net>
|
%%% Author : Badlop <badlop@process-one.net>
|
||||||
%%% Purpose : Extended Stanza Addressing (XEP-0033) support
|
%%% Purpose : Extended Stanza Addressing (XEP-0033) support
|
||||||
%%% Created : 29 May 2007 by Badlop <badlop@process-one.net>
|
%%% Created : 29 May 2007 by Badlop <badlop@process-one.net>
|
||||||
|
%%%
|
||||||
|
%%%
|
||||||
|
%%% ejabberd, Copyright (C) 2002-2015 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_multicast).
|
-module(mod_multicast).
|
||||||
@ -713,8 +731,7 @@ process_iqreply_error(From, LServiceS, _Packet) ->
|
|||||||
%%% Check protocol support: Receive response: Disco
|
%%% Check protocol support: Receive response: Disco
|
||||||
%%%-------------------------
|
%%%-------------------------
|
||||||
|
|
||||||
process_iqreply_result(From, LServiceS, Packet,
|
process_iqreply_result(From, LServiceS, Packet, State) ->
|
||||||
State) ->
|
|
||||||
#xmlel{name = <<"query">>, attrs = Attrs2,
|
#xmlel{name = <<"query">>, attrs = Attrs2,
|
||||||
children = Els2} =
|
children = Els2} =
|
||||||
xml:get_subtag(Packet, <<"query">>),
|
xml:get_subtag(Packet, <<"query">>),
|
||||||
@ -741,37 +758,35 @@ process_discoinfo_result(From, LServiceS, Els,
|
|||||||
|
|
||||||
process_discoinfo_result2(From, FromS, LServiceS, Els,
|
process_discoinfo_result2(From, FromS, LServiceS, Els,
|
||||||
Waiter) ->
|
Waiter) ->
|
||||||
Multicast_support = lists:any(fun (XML) ->
|
Multicast_support =
|
||||||
case XML of
|
lists:any(
|
||||||
#xmlel{name = <<"feature">>,
|
fun(XML) ->
|
||||||
attrs = Attrs} ->
|
case XML of
|
||||||
(?NS_ADDRESS) ==
|
#xmlel{name = <<"feature">>, attrs = Attrs} ->
|
||||||
xml:get_attr_s(<<"var">>,
|
(?NS_ADDRESS) == xml:get_attr_s(<<"var">>, Attrs);
|
||||||
Attrs);
|
_ -> false
|
||||||
_ -> false
|
end
|
||||||
end
|
end,
|
||||||
end,
|
Els),
|
||||||
Els),
|
|
||||||
Group = Waiter#waiter.group,
|
Group = Waiter#waiter.group,
|
||||||
RServer = Group#group.server,
|
RServer = Group#group.server,
|
||||||
case Multicast_support of
|
case Multicast_support of
|
||||||
true ->
|
true ->
|
||||||
SenderT = sender_type(From),
|
SenderT = sender_type(From),
|
||||||
RLimits = get_limits_xml(Els, SenderT),
|
RLimits = get_limits_xml(Els, SenderT),
|
||||||
add_response(RServer,
|
add_response(RServer, {multicast_supported, FromS, RLimits}),
|
||||||
{multicast_supported, FromS, RLimits}),
|
FromM = Waiter#waiter.sender,
|
||||||
FromM = Waiter#waiter.sender,
|
DestsM = Group#group.dests,
|
||||||
DestsM = Group#group.dests,
|
PacketM = Waiter#waiter.packet,
|
||||||
PacketM = Waiter#waiter.packet,
|
AAttrsM = Waiter#waiter.aattrs,
|
||||||
AAttrsM = Waiter#waiter.aattrs,
|
AddressesM = Waiter#waiter.addresses,
|
||||||
AddressesM = Waiter#waiter.addresses,
|
RServiceM = FromS,
|
||||||
RServiceM = FromS,
|
route_packet_multicast(FromM, RServiceM, PacketM,
|
||||||
route_packet_multicast(FromM, RServiceM, PacketM,
|
AAttrsM, DestsM, AddressesM, RLimits),
|
||||||
AAttrsM, DestsM, AddressesM, RLimits),
|
delo_waiter(Waiter);
|
||||||
delo_waiter(Waiter);
|
false ->
|
||||||
false ->
|
case FromS of
|
||||||
case FromS of
|
RServer ->
|
||||||
RServer ->
|
|
||||||
send_query_items(FromS, LServiceS),
|
send_query_items(FromS, LServiceS),
|
||||||
delo_waiter(Waiter),
|
delo_waiter(Waiter),
|
||||||
add_waiter(Waiter#waiter{awaiting =
|
add_waiter(Waiter#waiter{awaiting =
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
-export([count_offline_messages/2]).
|
-export([count_offline_messages/2]).
|
||||||
|
|
||||||
-export([start/2,
|
-export([start/2,
|
||||||
start_link/2,
|
start_link/2,
|
||||||
stop/1,
|
stop/1,
|
||||||
store_packet/3,
|
store_packet/3,
|
||||||
resend_offline_messages/2,
|
resend_offline_messages/2,
|
||||||
@ -48,11 +48,11 @@
|
|||||||
remove_expired_messages/1,
|
remove_expired_messages/1,
|
||||||
remove_old_messages/2,
|
remove_old_messages/2,
|
||||||
remove_user/2,
|
remove_user/2,
|
||||||
import/1,
|
import/1,
|
||||||
import/3,
|
import/3,
|
||||||
export/1,
|
export/1,
|
||||||
get_queue_length/2,
|
get_queue_length/2,
|
||||||
get_offline_els/2,
|
get_offline_els/2,
|
||||||
webadmin_page/3,
|
webadmin_page/3,
|
||||||
webadmin_user/4,
|
webadmin_user/4,
|
||||||
webadmin_user_parse_query/5]).
|
webadmin_user_parse_query/5]).
|
||||||
@ -70,17 +70,7 @@
|
|||||||
|
|
||||||
-include("ejabberd_web_admin.hrl").
|
-include("ejabberd_web_admin.hrl").
|
||||||
|
|
||||||
-record(offline_msg,
|
-include("mod_offline.hrl").
|
||||||
{us = {<<"">>, <<"">>} :: {binary(), binary()},
|
|
||||||
timestamp = now() :: erlang:timestamp() | '_',
|
|
||||||
expire = now() :: erlang:timestamp() | never | '_',
|
|
||||||
from = #jid{} :: jid() | '_',
|
|
||||||
to = #jid{} :: jid() | '_',
|
|
||||||
packet = #xmlel{} :: xmlel() | '_'}).
|
|
||||||
|
|
||||||
-record(state,
|
|
||||||
{host = <<"">> :: binary(),
|
|
||||||
access_max_offline_messages}).
|
|
||||||
|
|
||||||
-define(PROCNAME, ejabberd_offline).
|
-define(PROCNAME, ejabberd_offline).
|
||||||
|
|
||||||
@ -138,8 +128,11 @@ init([Host, Opts]) ->
|
|||||||
ejabberd_hooks:add(webadmin_user, Host,
|
ejabberd_hooks:add(webadmin_user, Host,
|
||||||
?MODULE, webadmin_user, 50),
|
?MODULE, webadmin_user, 50),
|
||||||
ejabberd_hooks:add(webadmin_user_parse_query, Host,
|
ejabberd_hooks:add(webadmin_user_parse_query, Host,
|
||||||
?MODULE, webadmin_user_parse_query, 50),
|
?MODULE, webadmin_user_parse_query, 50),
|
||||||
AccessMaxOfflineMsgs = gen_mod:get_opt(access_max_user_messages, Opts, fun(A) -> A end, max_user_offline_messages),
|
AccessMaxOfflineMsgs =
|
||||||
|
gen_mod:get_opt(access_max_user_messages, Opts,
|
||||||
|
fun(A) when is_atom(A) -> A end,
|
||||||
|
max_user_offline_messages),
|
||||||
{ok,
|
{ok,
|
||||||
#state{host = Host,
|
#state{host = Host,
|
||||||
access_max_offline_messages = AccessMaxOfflineMsgs}}.
|
access_max_offline_messages = AccessMaxOfflineMsgs}}.
|
||||||
@ -253,7 +246,6 @@ store_offline_msg(Host, {User, _}, Msgs, Len, MaxOfflineMsgs,
|
|||||||
end, Msgs)
|
end, Msgs)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Function copied from ejabberd_sm.erl:
|
|
||||||
get_max_user_messages(AccessRule, {User, Server}, Host) ->
|
get_max_user_messages(AccessRule, {User, Server}, Host) ->
|
||||||
case acl:match_rule(
|
case acl:match_rule(
|
||||||
Host, AccessRule, jlib:make_jid(User, Server, <<"">>)) of
|
Host, AccessRule, jlib:make_jid(User, Server, <<"">>)) of
|
||||||
@ -308,24 +300,24 @@ need_to_store(LServer, Packet) ->
|
|||||||
store_packet(From, To, Packet) ->
|
store_packet(From, To, Packet) ->
|
||||||
case need_to_store(To#jid.lserver, Packet) of
|
case need_to_store(To#jid.lserver, Packet) of
|
||||||
true ->
|
true ->
|
||||||
case has_no_store_hint(Packet) of
|
case has_no_store_hint(Packet) of
|
||||||
false ->
|
false ->
|
||||||
case check_event(From, To, Packet) of
|
case check_event(From, To, Packet) of
|
||||||
true ->
|
true ->
|
||||||
#jid{luser = LUser, lserver = LServer} = To,
|
#jid{luser = LUser, lserver = LServer} = To,
|
||||||
TimeStamp = now(),
|
TimeStamp = now(),
|
||||||
#xmlel{children = Els} = Packet,
|
#xmlel{children = Els} = Packet,
|
||||||
Expire = find_x_expire(TimeStamp, Els),
|
Expire = find_x_expire(TimeStamp, Els),
|
||||||
gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME) !
|
gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME) !
|
||||||
#offline_msg{us = {LUser, LServer},
|
#offline_msg{us = {LUser, LServer},
|
||||||
timestamp = TimeStamp, expire = Expire,
|
timestamp = TimeStamp, expire = Expire,
|
||||||
from = From, to = To, packet = Packet},
|
from = From, to = To, packet = Packet},
|
||||||
stop;
|
stop;
|
||||||
_ -> ok
|
_ -> ok
|
||||||
end;
|
end;
|
||||||
_ -> ok
|
_ -> ok
|
||||||
end;
|
end;
|
||||||
false -> ok
|
false -> ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
has_no_store_hint(Packet) ->
|
has_no_store_hint(Packet) ->
|
||||||
|
@ -584,11 +584,10 @@ process_list_set(LUser, LServer, {value, Name}, Els) ->
|
|||||||
ejabberd_sm:route(jlib:make_jid(LUser, LServer,
|
ejabberd_sm:route(jlib:make_jid(LUser, LServer,
|
||||||
<<"">>),
|
<<"">>),
|
||||||
jlib:make_jid(LUser, LServer, <<"">>),
|
jlib:make_jid(LUser, LServer, <<"">>),
|
||||||
{broadcast,
|
{broadcast, {privacy_list,
|
||||||
{privacy_list,
|
#userlist{name = Name,
|
||||||
#userlist{name = Name,
|
list = []},
|
||||||
list = []},
|
Name}}),
|
||||||
Name}}),
|
|
||||||
{result, []};
|
{result, []};
|
||||||
_ -> {error, ?ERR_INTERNAL_SERVER_ERROR}
|
_ -> {error, ?ERR_INTERNAL_SERVER_ERROR}
|
||||||
end;
|
end;
|
||||||
@ -601,12 +600,11 @@ process_list_set(LUser, LServer, {value, Name}, Els) ->
|
|||||||
ejabberd_sm:route(jlib:make_jid(LUser, LServer,
|
ejabberd_sm:route(jlib:make_jid(LUser, LServer,
|
||||||
<<"">>),
|
<<"">>),
|
||||||
jlib:make_jid(LUser, LServer, <<"">>),
|
jlib:make_jid(LUser, LServer, <<"">>),
|
||||||
{broadcast,
|
{broadcast, {privacy_list,
|
||||||
{privacy_list,
|
#userlist{name = Name,
|
||||||
#userlist{name = Name,
|
list = List,
|
||||||
list = List,
|
needdb = NeedDb},
|
||||||
needdb = NeedDb},
|
Name}}),
|
||||||
Name}}),
|
|
||||||
{result, []};
|
{result, []};
|
||||||
_ -> {error, ?ERR_INTERNAL_SERVER_ERROR}
|
_ -> {error, ?ERR_INTERNAL_SERVER_ERROR}
|
||||||
end
|
end
|
||||||
@ -1166,7 +1164,7 @@ update_table() ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
export(Server) ->
|
export(Server) ->
|
||||||
case ejabberd_odbc:sql_query(jlib:nameprep(Server),
|
case catch ejabberd_odbc:sql_query(jlib:nameprep(Server),
|
||||||
[<<"select id from privacy_list order by "
|
[<<"select id from privacy_list order by "
|
||||||
"id desc limit 1;">>]) of
|
"id desc limit 1;">>]) of
|
||||||
{selected, [<<"id">>], [[I]]} ->
|
{selected, [<<"id">>], [[I]]} ->
|
||||||
|
@ -64,8 +64,9 @@ start_link(Host, Opts) ->
|
|||||||
[]).
|
[]).
|
||||||
|
|
||||||
init([Opts]) ->
|
init([Opts]) ->
|
||||||
mnesia:create_table(bytestream, [{ram_copies, [node()]},
|
mnesia:create_table(bytestream,
|
||||||
{attributes, record_info(fields, bytestream)}]),
|
[{ram_copies, [node()]},
|
||||||
|
{attributes, record_info(fields, bytestream)}]),
|
||||||
mnesia:add_table_copy(bytestream, node(), ram_copies),
|
mnesia:add_table_copy(bytestream, node(), ram_copies),
|
||||||
MaxConnections = gen_mod:get_opt(max_connections, Opts,
|
MaxConnections = gen_mod:get_opt(max_connections, Opts,
|
||||||
fun(I) when is_integer(I), I>0 ->
|
fun(I) when is_integer(I), I>0 ->
|
||||||
|
@ -3480,10 +3480,9 @@ subscribed_nodes_by_jid(NotifyType, SubsByDepth) ->
|
|||||||
NodeOptions = Node#pubsub_node.options,
|
NodeOptions = Node#pubsub_node.options,
|
||||||
lists:foldl(fun({LJID, SubID, SubOptions}, {JIDs, Recipients}) ->
|
lists:foldl(fun({LJID, SubID, SubOptions}, {JIDs, Recipients}) ->
|
||||||
case is_to_deliver(LJID, NotifyType, Depth, NodeOptions, SubOptions) of
|
case is_to_deliver(LJID, NotifyType, Depth, NodeOptions, SubOptions) of
|
||||||
true ->
|
true ->
|
||||||
%% If is to deliver :
|
|
||||||
case state_can_deliver(LJID, SubOptions) of
|
case state_can_deliver(LJID, SubOptions) of
|
||||||
[] -> {JIDs, Recipients};
|
[] -> {JIDs, Recipients};
|
||||||
JIDsToDeliver ->
|
JIDsToDeliver ->
|
||||||
lists:foldl(
|
lists:foldl(
|
||||||
fun(JIDToDeliver, {JIDsAcc, RecipientsAcc}) ->
|
fun(JIDToDeliver, {JIDsAcc, RecipientsAcc}) ->
|
||||||
@ -3494,11 +3493,14 @@ subscribed_nodes_by_jid(NotifyType, SubsByDepth) ->
|
|||||||
%% - add the Jid to JIDs list co-accumulator ;
|
%% - add the Jid to JIDs list co-accumulator ;
|
||||||
%% - create a tuple of the Jid, Nidx, and SubID (as list),
|
%% - create a tuple of the Jid, Nidx, and SubID (as list),
|
||||||
%% and add the tuple to the Recipients list co-accumulator
|
%% and add the tuple to the Recipients list co-accumulator
|
||||||
{[JIDToDeliver | JIDsAcc], [{JIDToDeliver, NodeName, [SubID]} | RecipientsAcc]};
|
{[JIDToDeliver | JIDsAcc],
|
||||||
|
[{JIDToDeliver, NodeName, [SubID]}
|
||||||
|
| RecipientsAcc]};
|
||||||
true ->
|
true ->
|
||||||
%% - if the JIDs co-accumulator contains the Jid
|
%% - if the JIDs co-accumulator contains the Jid
|
||||||
%% get the tuple containing the Jid from the Recipient list co-accumulator
|
%% get the tuple containing the Jid from the Recipient list co-accumulator
|
||||||
{_, {JIDToDeliver, NodeName1, SubIDs}} = lists:keysearch(JIDToDeliver, 1, RecipientsAcc),
|
{_, {JIDToDeliver, NodeName1, SubIDs}} =
|
||||||
|
lists:keysearch(JIDToDeliver, 1, RecipientsAcc),
|
||||||
%% delete the tuple from the Recipients list
|
%% delete the tuple from the Recipients list
|
||||||
% v1 : Recipients1 = lists:keydelete(LJID, 1, Recipients),
|
% v1 : Recipients1 = lists:keydelete(LJID, 1, Recipients),
|
||||||
% v2 : Recipients1 = lists:keyreplace(LJID, 1, Recipients, {LJID, Nidx1, [SubID | SubIDs]}),
|
% v2 : Recipients1 = lists:keyreplace(LJID, 1, Recipients, {LJID, Nidx1, [SubID | SubIDs]}),
|
||||||
@ -3507,7 +3509,11 @@ subscribed_nodes_by_jid(NotifyType, SubsByDepth) ->
|
|||||||
% v1.1 : {JIDs, lists:append(Recipients1, [{LJID, Nidx1, lists:append(SubIDs, [SubID])}])}
|
% v1.1 : {JIDs, lists:append(Recipients1, [{LJID, Nidx1, lists:append(SubIDs, [SubID])}])}
|
||||||
% v1.2 : {JIDs, [{LJID, Nidx1, [SubID | SubIDs]} | Recipients1]}
|
% v1.2 : {JIDs, [{LJID, Nidx1, [SubID | SubIDs]} | Recipients1]}
|
||||||
% v2: {JIDs, Recipients1}
|
% v2: {JIDs, Recipients1}
|
||||||
{JIDsAcc, lists:keyreplace(JIDToDeliver, 1, RecipientsAcc, {JIDToDeliver, NodeName1, [SubID | SubIDs]})}
|
{JIDsAcc,
|
||||||
|
lists:keyreplace(JIDToDeliver, 1,
|
||||||
|
RecipientsAcc,
|
||||||
|
{JIDToDeliver, NodeName1,
|
||||||
|
[SubID | SubIDs]})}
|
||||||
end
|
end
|
||||||
end, {JIDs, Recipients}, JIDsToDeliver)
|
end, {JIDs, Recipients}, JIDsToDeliver)
|
||||||
end;
|
end;
|
||||||
|
@ -408,6 +408,8 @@ try_register(User, Server, Password, SourceRaw, Lang) ->
|
|||||||
{error, ?ERR_JID_MALFORMED};
|
{error, ?ERR_JID_MALFORMED};
|
||||||
{error, not_allowed} ->
|
{error, not_allowed} ->
|
||||||
{error, ?ERR_NOT_ALLOWED};
|
{error, ?ERR_NOT_ALLOWED};
|
||||||
|
{error, too_many_users} ->
|
||||||
|
{error, ?ERR_NOT_ALLOWED};
|
||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
{error, ?ERR_INTERNAL_SERVER_ERROR}
|
{error, ?ERR_INTERNAL_SERVER_ERROR}
|
||||||
end
|
end
|
||||||
|
@ -1005,7 +1005,6 @@ send_unsubscription_to_rosteritems(LUser, LServer) ->
|
|||||||
end,
|
end,
|
||||||
RosterItems).
|
RosterItems).
|
||||||
|
|
||||||
%% @spec (From::jid(), Item::roster()) -> ok
|
|
||||||
send_unsubscribing_presence(From, Item) ->
|
send_unsubscribing_presence(From, Item) ->
|
||||||
IsTo = case Item#roster.subscription of
|
IsTo = case Item#roster.subscription of
|
||||||
both -> true;
|
both -> true;
|
||||||
|
@ -98,9 +98,6 @@ start(Host, Opts) ->
|
|||||||
ejabberd_hooks:add(remove_user, Host, ?MODULE,
|
ejabberd_hooks:add(remove_user, Host, ?MODULE,
|
||||||
remove_user, 50).
|
remove_user, 50).
|
||||||
|
|
||||||
%%ejabberd_hooks:add(remove_user, Host,
|
|
||||||
%% ?MODULE, remove_user, 50),
|
|
||||||
|
|
||||||
stop(Host) ->
|
stop(Host) ->
|
||||||
ejabberd_hooks:delete(webadmin_menu_host, Host, ?MODULE,
|
ejabberd_hooks:delete(webadmin_menu_host, Host, ?MODULE,
|
||||||
webadmin_menu, 70),
|
webadmin_menu, 70),
|
||||||
@ -126,12 +123,11 @@ stop(Host) ->
|
|||||||
register_user, 50),
|
register_user, 50),
|
||||||
ejabberd_hooks:delete(anonymous_purge_hook, Host,
|
ejabberd_hooks:delete(anonymous_purge_hook, Host,
|
||||||
?MODULE, remove_user, 50),
|
?MODULE, remove_user, 50),
|
||||||
%%ejabberd_hooks:delete(remove_user, Host,
|
|
||||||
%% ?MODULE, remove_user, 50),
|
|
||||||
ejabberd_hooks:delete(remove_user, Host, ?MODULE,
|
ejabberd_hooks:delete(remove_user, Host, ?MODULE,
|
||||||
remove_user,
|
remove_user,
|
||||||
50).%%ejabberd_hooks:delete(remove_user, Host,
|
50).
|
||||||
%% ?MODULE, remove_user, 50),
|
%%ejabberd_hooks:delete(remove_user, Host,
|
||||||
|
%% ?MODULE, remove_user, 50),
|
||||||
|
|
||||||
get_user_roster(Items, US) ->
|
get_user_roster(Items, US) ->
|
||||||
{U, S} = US,
|
{U, S} = US,
|
||||||
@ -622,7 +618,6 @@ get_group_users(Host1, Group1) ->
|
|||||||
|
|
||||||
get_group_users(Host, Group, GroupOpts) ->
|
get_group_users(Host, Group, GroupOpts) ->
|
||||||
case proplists:get_value(all_users, GroupOpts, false) of
|
case proplists:get_value(all_users, GroupOpts, false) of
|
||||||
%% @spec (Host::string(), Group::string()) -> [{User::string(), Server::string()}]
|
|
||||||
true -> ejabberd_auth:get_vh_registered_users(Host);
|
true -> ejabberd_auth:get_vh_registered_users(Host);
|
||||||
false -> []
|
false -> []
|
||||||
end
|
end
|
||||||
@ -675,25 +670,22 @@ get_group_name(Host1, Group1) ->
|
|||||||
|
|
||||||
%% Get list of names of groups that have @all@/@online@/etc in the memberlist
|
%% Get list of names of groups that have @all@/@online@/etc in the memberlist
|
||||||
get_special_users_groups(Host) ->
|
get_special_users_groups(Host) ->
|
||||||
%% Get list of names of groups that have @online@ in the memberlist
|
|
||||||
lists:filter(fun (Group) ->
|
lists:filter(fun (Group) ->
|
||||||
get_group_opt(Host, Group, all_users, false) orelse
|
get_group_opt(Host, Group, all_users, false) orelse
|
||||||
get_group_opt(Host, Group, online_users, false)
|
get_group_opt(Host, Group, online_users, false)
|
||||||
end,
|
end,
|
||||||
list_groups(Host)).
|
list_groups(Host)).
|
||||||
|
|
||||||
|
%% Get list of names of groups that have @online@ in the memberlist
|
||||||
get_special_users_groups_online(Host) ->
|
get_special_users_groups_online(Host) ->
|
||||||
%% Given two lists of groupnames and their options,
|
|
||||||
%% return the list of displayed groups to the second list
|
|
||||||
lists:filter(fun (Group) ->
|
lists:filter(fun (Group) ->
|
||||||
get_group_opt(Host, Group, online_users, false)
|
get_group_opt(Host, Group, online_users, false)
|
||||||
end,
|
end,
|
||||||
list_groups(Host)).
|
list_groups(Host)).
|
||||||
|
|
||||||
|
%% Given two lists of groupnames and their options,
|
||||||
|
%% return the list of displayed groups to the second list
|
||||||
displayed_groups(GroupsOpts, SelectedGroupsOpts) ->
|
displayed_groups(GroupsOpts, SelectedGroupsOpts) ->
|
||||||
%% Given a list of group names with options,
|
|
||||||
%% for those that have @all@ in memberlist,
|
|
||||||
%% get the list of groups displayed
|
|
||||||
DisplayedGroups = lists:usort(lists:flatmap(fun
|
DisplayedGroups = lists:usort(lists:flatmap(fun
|
||||||
({_Group, Opts}) ->
|
({_Group, Opts}) ->
|
||||||
[G
|
[G
|
||||||
@ -712,6 +704,9 @@ displayed_groups(GroupsOpts, SelectedGroupsOpts) ->
|
|||||||
lists:member(disabled,
|
lists:member(disabled,
|
||||||
proplists:get_value(G, GroupsOpts, []))].
|
proplists:get_value(G, GroupsOpts, []))].
|
||||||
|
|
||||||
|
%% Given a list of group names with options,
|
||||||
|
%% for those that have @all@ in memberlist,
|
||||||
|
%% get the list of groups displayed
|
||||||
get_special_displayed_groups(GroupsOpts) ->
|
get_special_displayed_groups(GroupsOpts) ->
|
||||||
Groups = lists:filter(fun ({_Group, Opts}) ->
|
Groups = lists:filter(fun ({_Group, Opts}) ->
|
||||||
proplists:get_value(all_users, Opts, false)
|
proplists:get_value(all_users, Opts, false)
|
||||||
@ -825,7 +820,7 @@ is_user_in_group(US, Group, Host, odbc) ->
|
|||||||
%% @spec (Host::string(), {User::string(), Server::string()}, Group::string()) -> {atomic, ok}
|
%% @spec (Host::string(), {User::string(), Server::string()}, Group::string()) -> {atomic, ok}
|
||||||
add_user_to_group(Host, US, Group) ->
|
add_user_to_group(Host, US, Group) ->
|
||||||
{LUser, LServer} = US,
|
{LUser, LServer} = US,
|
||||||
case ejabberd_regexp:run(LUser, <<"^@.+@$">>) of
|
case ejabberd_regexp:run(LUser, <<"^@.+@\$">>) of
|
||||||
match ->
|
match ->
|
||||||
GroupOpts = (?MODULE):get_group_opts(Host, Group),
|
GroupOpts = (?MODULE):get_group_opts(Host, Group),
|
||||||
MoreGroupOpts = case LUser of
|
MoreGroupOpts = case LUser of
|
||||||
@ -884,7 +879,7 @@ push_displayed_to_user(LUser, LServer, Host, Subscription, DisplayedGroups) ->
|
|||||||
|
|
||||||
remove_user_from_group(Host, US, Group) ->
|
remove_user_from_group(Host, US, Group) ->
|
||||||
{LUser, LServer} = US,
|
{LUser, LServer} = US,
|
||||||
case ejabberd_regexp:run(LUser, <<"^@.+@$">>) of
|
case ejabberd_regexp:run(LUser, <<"^@.+@\$">>) of
|
||||||
match ->
|
match ->
|
||||||
GroupOpts = (?MODULE):get_group_opts(Host, Group),
|
GroupOpts = (?MODULE):get_group_opts(Host, Group),
|
||||||
NewGroupOpts = case LUser of
|
NewGroupOpts = case LUser of
|
||||||
|
@ -275,16 +275,9 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
|||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% For a given user, map all his shared roster contacts to groups they are
|
|
||||||
%% members of. Skip the user himself iff SkipUS is true.
|
|
||||||
get_user_to_groups_map({_, Server} = US, SkipUS) ->
|
get_user_to_groups_map({_, Server} = US, SkipUS) ->
|
||||||
DisplayedGroups = get_user_displayed_groups(US),
|
DisplayedGroups = get_user_displayed_groups(US),
|
||||||
%% Pass given FilterParseArgs to eldap_filter:parse, and if successful, run and
|
|
||||||
%% return the resulting filter, retrieving given AttributesList. Return the
|
|
||||||
%% result entries. On any error silently return an empty list of results.
|
|
||||||
%%
|
|
||||||
%% Eldap server ID and base DN for the query are both retrieved from the State
|
|
||||||
%% record.
|
|
||||||
lists:foldl(fun (Group, Dict1) ->
|
lists:foldl(fun (Group, Dict1) ->
|
||||||
GroupName = get_group_name(Server, Group),
|
GroupName = get_group_name(Server, Group),
|
||||||
lists:foldl(fun (Contact, Dict) ->
|
lists:foldl(fun (Contact, Dict) ->
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
|
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||||
%%% @copyright (C) 2014, Evgeny Khramtsov
|
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%%
|
%%%
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% Created : 21 Apr 2014 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
%%% Created : 21 Apr 2014 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2014-2015 ProcessOne
|
%%% ejabberd, Copyright (C) 2014-2015 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
|
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||||
%%% @copyright (C) 2014, Evgeny Khramtsov
|
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%%
|
%%%
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% Created : 21 Apr 2014 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
%%% Created : 21 Apr 2014 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2014-2015 ProcessOne
|
%%% ejabberd, Copyright (C) 2014-2015 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
|
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||||
%%% @copyright (C) 2014, Evgeny Khramtsov
|
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%%
|
%%%
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% Created : 23 Apr 2014 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
%%% Created : 23 Apr 2014 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2014-2015 ProcessOne
|
%%% ejabberd, Copyright (C) 2014-2015 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
|
@ -175,7 +175,7 @@ get_local_stat(_Server, _, Name) ->
|
|||||||
|
|
||||||
get_node_stat(Node, Name)
|
get_node_stat(Node, Name)
|
||||||
when Name == <<"time/uptime">> ->
|
when Name == <<"time/uptime">> ->
|
||||||
case catch rpc:call(Node, erlang, statistics,
|
case catch ejabberd_cluster:call(Node, erlang, statistics,
|
||||||
[wall_clock])
|
[wall_clock])
|
||||||
of
|
of
|
||||||
{badrpc, _Reason} ->
|
{badrpc, _Reason} ->
|
||||||
@ -188,7 +188,7 @@ get_node_stat(Node, Name)
|
|||||||
end;
|
end;
|
||||||
get_node_stat(Node, Name)
|
get_node_stat(Node, Name)
|
||||||
when Name == <<"time/cputime">> ->
|
when Name == <<"time/cputime">> ->
|
||||||
case catch rpc:call(Node, erlang, statistics, [runtime])
|
case catch ejabberd_cluster:call(Node, erlang, statistics, [runtime])
|
||||||
of
|
of
|
||||||
{badrpc, _Reason} ->
|
{badrpc, _Reason} ->
|
||||||
?STATERR(<<"500">>, <<"Internal Server Error">>);
|
?STATERR(<<"500">>, <<"Internal Server Error">>);
|
||||||
@ -200,7 +200,7 @@ get_node_stat(Node, Name)
|
|||||||
end;
|
end;
|
||||||
get_node_stat(Node, Name)
|
get_node_stat(Node, Name)
|
||||||
when Name == <<"users/online">> ->
|
when Name == <<"users/online">> ->
|
||||||
case catch rpc:call(Node, ejabberd_sm,
|
case catch ejabberd_cluster:call(Node, ejabberd_sm,
|
||||||
dirty_get_my_sessions_list, [])
|
dirty_get_my_sessions_list, [])
|
||||||
of
|
of
|
||||||
{badrpc, _Reason} ->
|
{badrpc, _Reason} ->
|
||||||
@ -211,7 +211,7 @@ get_node_stat(Node, Name)
|
|||||||
end;
|
end;
|
||||||
get_node_stat(Node, Name)
|
get_node_stat(Node, Name)
|
||||||
when Name == <<"transactions/committed">> ->
|
when Name == <<"transactions/committed">> ->
|
||||||
case catch rpc:call(Node, mnesia, system_info,
|
case catch ejabberd_cluster:call(Node, mnesia, system_info,
|
||||||
[transaction_commits])
|
[transaction_commits])
|
||||||
of
|
of
|
||||||
{badrpc, _Reason} ->
|
{badrpc, _Reason} ->
|
||||||
@ -222,7 +222,7 @@ get_node_stat(Node, Name)
|
|||||||
end;
|
end;
|
||||||
get_node_stat(Node, Name)
|
get_node_stat(Node, Name)
|
||||||
when Name == <<"transactions/aborted">> ->
|
when Name == <<"transactions/aborted">> ->
|
||||||
case catch rpc:call(Node, mnesia, system_info,
|
case catch ejabberd_cluster:call(Node, mnesia, system_info,
|
||||||
[transaction_failures])
|
[transaction_failures])
|
||||||
of
|
of
|
||||||
{badrpc, _Reason} ->
|
{badrpc, _Reason} ->
|
||||||
@ -233,7 +233,7 @@ get_node_stat(Node, Name)
|
|||||||
end;
|
end;
|
||||||
get_node_stat(Node, Name)
|
get_node_stat(Node, Name)
|
||||||
when Name == <<"transactions/restarted">> ->
|
when Name == <<"transactions/restarted">> ->
|
||||||
case catch rpc:call(Node, mnesia, system_info,
|
case catch ejabberd_cluster:call(Node, mnesia, system_info,
|
||||||
[transaction_restarts])
|
[transaction_restarts])
|
||||||
of
|
of
|
||||||
{badrpc, _Reason} ->
|
{badrpc, _Reason} ->
|
||||||
@ -244,7 +244,7 @@ get_node_stat(Node, Name)
|
|||||||
end;
|
end;
|
||||||
get_node_stat(Node, Name)
|
get_node_stat(Node, Name)
|
||||||
when Name == <<"transactions/logged">> ->
|
when Name == <<"transactions/logged">> ->
|
||||||
case catch rpc:call(Node, mnesia, system_info,
|
case catch ejabberd_cluster:call(Node, mnesia, system_info,
|
||||||
[transaction_log_writes])
|
[transaction_log_writes])
|
||||||
of
|
of
|
||||||
{badrpc, _Reason} ->
|
{badrpc, _Reason} ->
|
||||||
|
@ -54,7 +54,8 @@ init(Host, ServerHost, Opts) ->
|
|||||||
ok.
|
ok.
|
||||||
|
|
||||||
terminate(Host, ServerHost) ->
|
terminate(Host, ServerHost) ->
|
||||||
node_flat:terminate(Host, ServerHost), ok.
|
node_flat:terminate(Host, ServerHost),
|
||||||
|
ok.
|
||||||
|
|
||||||
options() ->
|
options() ->
|
||||||
[{deliver_payloads, true},
|
[{deliver_payloads, true},
|
||||||
|
@ -55,7 +55,8 @@ init(Host, ServerHost, Opts) ->
|
|||||||
ok.
|
ok.
|
||||||
|
|
||||||
terminate(Host, ServerHost) ->
|
terminate(Host, ServerHost) ->
|
||||||
node_flat_odbc:terminate(Host, ServerHost), ok.
|
node_flat_odbc:terminate(Host, ServerHost),
|
||||||
|
ok.
|
||||||
|
|
||||||
options() ->
|
options() ->
|
||||||
[{odbc, true}, {rsm, true} | node_pep:options()].
|
[{odbc, true}, {rsm, true} | node_pep:options()].
|
||||||
|
Loading…
Reference in New Issue
Block a user