25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-24 16:23:40 +01:00

cosmetic cleanup

This commit is contained in:
Christophe Romain 2015-10-07 00:06:58 +02:00
parent 83dd79a6a7
commit 6aeb9dcb38
59 changed files with 1275 additions and 1907 deletions

View File

@ -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
View 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}).

View File

@ -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) ->

View File

@ -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)).

View File

@ -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, _) ->

View File

@ -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;

View File

@ -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'

View File

@ -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
View 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).

View File

@ -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).

View File

@ -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);

View File

@ -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;

View File

@ -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};

View File

@ -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}]),

View File

@ -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

View File

@ -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)].

View File

@ -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",

View File

@ -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

View File

@ -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.

View File

@ -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].

View File

@ -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}.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------

View File

@ -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

View File

@ -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}),

View File

@ -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).

View File

@ -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

View File

@ -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.
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------

View File

@ -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()}}.

View File

@ -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),

View File

@ -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

View File

@ -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
%%====================================================================
%====================================================================

View File

@ -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} ->

View File

@ -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

View File

@ -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=%%%%,%%%=:

View File

@ -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) ->

View File

@ -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}.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------

View File

@ -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'}}]}]).

View File

@ -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} ->

View File

@ -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

View File

@ -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, <<".">>),

View File

@ -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) ->

View File

@ -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]) ->

View File

@ -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),

View File

@ -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()),

View File

@ -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).

View File

@ -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 =

View File

@ -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) ->

View File

@ -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]]} ->

View File

@ -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 ->

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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) ->

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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} ->

View File

@ -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},

View File

@ -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()].