25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-30 16:36:29 +01:00

First bunch of modifications to use exmpp. All FSM state function are

updated. But other functions are not for now.

Users are able to connect to ejabberd but some features may not work.

SVN Revision: 1368
This commit is contained in:
Jean-Sébastien Pédron 2008-06-20 12:52:29 +00:00
parent a19f280fcc
commit 389b5e6448
2 changed files with 440 additions and 429 deletions

View File

@ -4,6 +4,10 @@
* src/ejabberd_receiver.erl: Enable the new #xmlel record. * src/ejabberd_receiver.erl: Enable the new #xmlel record.
* src/ejabberd_c2s.erl: First bunch of modifications to use exmpp. All
FSM state function are updated. But other functions are not for now.
Users are able to connect to ejabberd but some features may not work.
2008-06-19 Jean-Sébastien Pédron <js.pedron@meetic-corp.com> 2008-06-19 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
* src/ejabberd_receiver.erl: Replace the use of xml_stream by * src/ejabberd_receiver.erl: Replace the use of xml_stream by

View File

@ -54,8 +54,9 @@
handle_info/3, handle_info/3,
terminate/3]). terminate/3]).
-include("exmpp.hrl").
-include("ejabberd.hrl"). -include("ejabberd.hrl").
-include("jlib.hrl").
-include("mod_privacy.hrl"). -include("mod_privacy.hrl").
-define(SETS, gb_sets). -define(SETS, gb_sets).
@ -93,11 +94,11 @@
%-define(DBGFSM, true). %-define(DBGFSM, true).
-ifdef(DBGFSM). %-ifdef(DBGFSM).
-define(FSMOPTS, [{debug, [trace]}]). -define(FSMOPTS, [{debug, [trace]}]).
-else. %-else.
-define(FSMOPTS, []). %-define(FSMOPTS, []).
-endif. %-endif.
%% Module start with or without supervisor: %% Module start with or without supervisor:
-ifdef(NO_TRANSIENT_SUPERVISORS). -ifdef(NO_TRANSIENT_SUPERVISORS).
@ -113,6 +114,11 @@
-define(C2S_OPEN_TIMEOUT, 60000). -define(C2S_OPEN_TIMEOUT, 60000).
-define(C2S_HIBERNATE_TIMEOUT, 90000). -define(C2S_HIBERNATE_TIMEOUT, 90000).
% These are the namespace already declared by the stream opening. This is
% used at serialization time.
-define(DEFAULT_NS, ['jabber:client']).
-define(PREFIXED_NS, [{?NS_XMPP, "stream"}]).
-define(STREAM_HEADER, -define(STREAM_HEADER,
"<?xml version='1.0'?>" "<?xml version='1.0'?>"
"<stream:stream xmlns='jabber:client' " "<stream:stream xmlns='jabber:client' "
@ -131,6 +137,50 @@
-define(POLICY_VIOLATION_ERR(Lang, Text), -define(POLICY_VIOLATION_ERR(Lang, Text),
xml:element_to_string(?SERRT_POLICY_VIOLATION(Lang, Text))). xml:element_to_string(?SERRT_POLICY_VIOLATION(Lang, Text))).
% XXX OLD FORMAT
-define(NS_STREAM, "http://etherx.jabber.org/streams").
-define(NS_AUTH, "jabber:iq:auth").
-define(NS_FEATURE_COMPRESS, "http://jabber.org/features/compress").
-define(NS_PRIVACY, "jabber:iq:privacy").
-define(NS_VCARD, "vcard-temp").
-define(STREAM_ERROR(Condition),
exmpp_xml:xmlel_to_xmlelement(exmpp_stream:error(Condition),
[?NS_JABBER_CLIENT], [{?NS_XMPP, "stream"}])).
-define(SERR_XML_NOT_WELL_FORMED, ?STREAM_ERROR('xml-not-well-formed')).
-define(SERR_HOST_UNKNOWN, ?STREAM_ERROR('host-unknown')).
-define(SERR_INVALID_NAMESPACE, ?STREAM_ERROR('invalid-namespace')).
-define(STREAM_ERRORT(Condition, Lang, Text),
exmpp_xml:xmlel_to_xmlelement(exmpp_stream:error(Condition, {Lang, Text}),
[?NS_JABBER_CLIENT], [{?NS_XMPP, "stream"}])).
-define(SERRT_POLICY_VIOLATION(Lang, Text),
?STREAM_ERRORT('policy-violation', Lang, Text)).
-define(SERRT_CONFLICT(Lang, Text),
?STREAM_ERRORT('conflict', Lang, Text)).
-define(STANZA_ERROR(Condition),
exmpp_xml:xmlel_to_xmlelement(exmpp_stanza:error(Condition),
[?NS_JABBER_CLIENT], [{?NS_XMPP, "stream"}])).
-define(ERR_BAD_REQUEST, ?STANZA_ERROR('bad-request')).
-define(ERR_NOT_ALLOWED, ?STANZA_ERROR('not-allowed')).
-define(ERR_JID_MALFORMED, ?STANZA_ERROR('jid-malformed')).
-define(ERR_NOT_AUTHORIZED, ?STANZA_ERROR('not-authorized')).
-define(ERR_FEATURE_NOT_IMPLEMENTED, ?STANZA_ERROR('feature-not-implemented')).
-define(ERR_SERVICE_UNAVAILABLE, ?STANZA_ERROR('service-unavialable')).
-define(STANZA_ERRORT(Condition, Lang, Text),
exmpp_xml:xmlel_to_xmlelement(exmpp_stanza:error(Condition, {Lang, Text}),
[?NS_JABBER_CLIENT], [{?NS_XMPP, "stream"}])).
-define(ERR_AUTH_NO_RESOURCE_PROVIDED(Lang),
?STANZA_ERRORT('not-acceptable', Lang, "No resource provided")).
-record(iq, {id = "",
type,
xmlns = "",
lang = "",
sub_el}).
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
%%% API %%% API
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
@ -220,28 +270,28 @@ get_subscribed_and_online(FsmRef) ->
%% {stop, Reason, NewStateData} %% {stop, Reason, NewStateData}
%%---------------------------------------------------------------------- %%----------------------------------------------------------------------
wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) ->
DefaultLang = case ?MYLANG of DefaultLang = case ?MYLANG of
undefined -> undefined ->
" xml:lang='en'"; " xml:lang='en'";
DL -> DL ->
" xml:lang='" ++ DL ++ "'" " xml:lang='" ++ DL ++ "'"
end, end,
case xml:get_attr_s("xmlns:stream", Attrs) of Header = exmpp_stream:opening_reply(Opening,
?NS_STREAM -> StateData#state.streamid),
Server = jlib:nameprep(xml:get_attr_s("to", Attrs)), Header1 = exmpp_stream:set_lang(Header, DefaultLang),
case NS of
?NS_XMPP ->
Server = exmpp_stringprep:nameprep(
exmpp_stream:get_receiving_entity(Opening)),
case lists:member(Server, ?MYHOSTS) of case lists:member(Server, ?MYHOSTS) of
true -> true ->
Lang = xml:get_attr_s("xml:lang", Attrs), Lang = exmpp_stream:get_lang(Opening),
change_shaper(StateData, jlib:make_jid("", Server, "")), change_shaper(StateData,
case xml:get_attr_s("version", Attrs) of exmpp_jid:make_jid("", Server, "")),
"1.0" -> case exmpp_stream:get_version(Opening) of
Header = io_lib:format(?STREAM_HEADER, {1, 0} ->
[StateData#state.streamid, send_element(StateData, Header1),
Server,
" version='1.0'",
DefaultLang]),
send_text(StateData, Header),
case StateData#state.authenticated of case StateData#state.authenticated of
false -> false ->
SASLState = SASLState =
@ -255,11 +305,8 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
ejabberd_auth:check_password_with_authmodule( ejabberd_auth:check_password_with_authmodule(
U, Server, P) U, Server, P)
end), end),
Mechs = lists:map( SASL_Mechs = [exmpp_server_sasl:feature(
fun(S) -> cyrsasl:listmech(Server))],
{xmlelement, "mechanism", [],
[{xmlcdata, S}]}
end, cyrsasl:listmech(Server)),
SockMod = SockMod =
(StateData#state.sockmod):get_sockmod( (StateData#state.sockmod):get_sockmod(
StateData#state.socket), StateData#state.socket),
@ -268,10 +315,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
case Zlib andalso case Zlib andalso
(SockMod == gen_tcp) of (SockMod == gen_tcp) of
true -> true ->
[{xmlelement, "compression", [exmpp_server_compression:feature(["zlib"])];
[{"xmlns", ?NS_FEATURE_COMPRESS}],
[{xmlelement, "method",
[], [{xmlcdata, "zlib"}]}]}];
_ -> _ ->
[] []
end, end,
@ -283,29 +327,19 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
(TLSEnabled == false) andalso (TLSEnabled == false) andalso
(SockMod == gen_tcp) of (SockMod == gen_tcp) of
true -> true ->
case TLSRequired of [exmpp_server_tls:feature(TLSRequired)];
true ->
[{xmlelement, "starttls",
[{"xmlns", ?NS_TLS}],
[{xmlelement, "required",
[], []}]}];
_ ->
[{xmlelement, "starttls",
[{"xmlns", ?NS_TLS}], []}]
end;
false -> false ->
[] []
end, end,
send_element(StateData, send_element(StateData,
{xmlelement, "stream:features", [], exmpp_stream:features(
TLSFeature ++ CompressFeature ++ TLSFeature ++
[{xmlelement, "mechanisms", CompressFeature ++
[{"xmlns", ?NS_SASL}], SASL_Mechs ++
Mechs}] ++
ejabberd_hooks:run_fold( ejabberd_hooks:run_fold(
c2s_stream_features, c2s_stream_features,
Server, Server,
[], [])}), [], []))),
fsm_next_state(wait_for_feature_request, fsm_next_state(wait_for_feature_request,
StateData#state{ StateData#state{
server = Server, server = Server,
@ -316,11 +350,10 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
"" -> "" ->
send_element( send_element(
StateData, StateData,
{xmlelement, "stream:features", [], exmpp_stream:features([
[{xmlelement, "bind", exmpp_server_binding:feature(),
[{"xmlns", ?NS_BIND}], []}, exmpp_server_session:feature()
{xmlelement, "session", ])),
[{"xmlns", ?NS_SESSION}], []}]}),
fsm_next_state(wait_for_bind, fsm_next_state(wait_for_bind,
StateData#state{ StateData#state{
server = Server, server = Server,
@ -328,7 +361,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
_ -> _ ->
send_element( send_element(
StateData, StateData,
{xmlelement, "stream:features", [], []}), exmpp_stream:features([])),
fsm_next_state(wait_for_session, fsm_next_state(wait_for_session,
StateData#state{ StateData#state{
server = Server, server = Server,
@ -336,22 +369,16 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
end end
end; end;
_ -> _ ->
Header = io_lib:format(
?STREAM_HEADER,
[StateData#state.streamid, Server, "",
DefaultLang]),
if if
(not StateData#state.tls_enabled) and (not StateData#state.tls_enabled) and
StateData#state.tls_required -> StateData#state.tls_required ->
send_text(StateData, send_element(StateData,
Header ++ exmpp_xml:append_child(Header1,
?POLICY_VIOLATION_ERR( exmpp_stream:error('policy-violation',
Lang, Lang, "Use of STARTTLS required"))),
"Use of STARTTLS required") ++
?STREAM_TRAILER),
{stop, normal, StateData}; {stop, normal, StateData};
true -> true ->
send_text(StateData, Header), send_element(StateData, Header1),
fsm_next_state(wait_for_auth, fsm_next_state(wait_for_auth,
StateData#state{ StateData#state{
server = Server, server = Server,
@ -359,20 +386,16 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
end end
end; end;
_ -> _ ->
Header = io_lib:format( Header2 = exmpp_stream:set_initiating_entity(Header1,
?STREAM_HEADER, ?MYNAME),
[StateData#state.streamid, ?MYNAME, "", send_element(StateData, exmpp_xml:append_child(Header2,
DefaultLang]), exmpp_stream:error('host-unknown'))),
send_text(StateData,
Header ++ ?HOST_UNKNOWN_ERR ++ ?STREAM_TRAILER),
{stop, normal, StateData} {stop, normal, StateData}
end; end;
_ -> _ ->
Header = io_lib:format( Header2 = exmpp_stream:set_initiating_entity(Header1, ?MYNAME),
?STREAM_HEADER, send_element(StateData, exmpp_xml:append_child(Header2,
[StateData#state.streamid, ?MYNAME, "", DefaultLang]), exmpp_stream:error('invalid-namespace'))),
send_text(StateData,
Header ++ ?INVALID_NS_ERR ++ ?STREAM_TRAILER),
{stop, normal, StateData} {stop, normal, StateData}
end; end;
@ -380,18 +403,21 @@ wait_for_stream(timeout, StateData) ->
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_stream({xmlstreamelement, _}, StateData) -> wait_for_stream({xmlstreamelement, _}, StateData) ->
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
send_element(StateData, exmpp_stream:closing()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_stream({xmlstreamend, _}, StateData) -> wait_for_stream({xmlstreamend, _}, StateData) ->
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
send_element(StateData, exmpp_stream:closing()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_stream({xmlstreamerror, _}, StateData) -> wait_for_stream({xmlstreamerror, _}, StateData) ->
Header = io_lib:format(?STREAM_HEADER, Header = exmpp_stream:opening_reply(?MYNAME, 'jabber:client', "1.0",
["none", ?MYNAME, " version='1.0'", ""]), "none"),
send_text(StateData, Header1 = exmpp_xml:append_child(Header,
Header ++ ?INVALID_XML_ERR ++ ?STREAM_TRAILER), exmpp_stream:error('xml-not-well-formed')),
send_element(StateData, Header1),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_stream(closed, StateData) -> wait_for_stream(closed, StateData) ->
@ -400,46 +426,26 @@ wait_for_stream(closed, 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, _, _, _}} ->
{xmlelement, Name, Attrs, _Els} = jlib:make_result_iq_reply(El), Fields = case ejabberd_auth:plain_password_required(
case U of
"" ->
UCdata = [];
_ ->
UCdata = [{xmlcdata, U}]
end,
Res = case ejabberd_auth:plain_password_required(
StateData#state.server) of StateData#state.server) of
false -> false -> both;
{xmlelement, Name, Attrs, true -> plain
[{xmlelement, "query", [{"xmlns", ?NS_AUTH}],
[{xmlelement, "username", [], UCdata},
{xmlelement, "password", [], []},
{xmlelement, "digest", [], []},
{xmlelement, "resource", [], []}
]}]};
true ->
{xmlelement, Name, Attrs,
[{xmlelement, "query", [{"xmlns", ?NS_AUTH}],
[{xmlelement, "username", [], UCdata},
{xmlelement, "password", [], []},
{xmlelement, "resource", [], []}
]}]}
end, end,
send_element(StateData, Res), send_element(StateData,
exmpp_server_legacy_auth:fields(El, Fields)),
fsm_next_state(wait_for_auth, StateData); fsm_next_state(wait_for_auth, StateData);
{auth, _ID, set, {_U, _P, _D, ""}} -> {auth, _ID, set, {_U, _P, _D, ""}} ->
Err = jlib:make_error_reply( Err = exmpp_stanza:error('not-acceptable',
El, {StateData#state.lang, "No resource provided"}),
?ERR_AUTH_NO_RESOURCE_PROVIDED(StateData#state.lang)), send_element(StateData, exmpp_iq:error(El, Err)),
send_element(StateData, Err),
fsm_next_state(wait_for_auth, StateData); fsm_next_state(wait_for_auth, StateData);
{auth, _ID, set, {U, P, D, R}} -> {auth, _ID, set, {U, P, D, R}} ->
JID = jlib:make_jid(U, StateData#state.server, R), try
case (JID /= error) andalso JID = exmpp_jid:make_jid(U, StateData#state.server, R),
(acl:match_rule(StateData#state.server, case acl:match_rule(StateData#state.server,
StateData#state.access, JID) == allow) of StateData#state.access, JID) of
true -> allow ->
case ejabberd_auth:check_password_with_authmodule( case ejabberd_auth:check_password_with_authmodule(
U, StateData#state.server, P, U, StateData#state.server, P,
StateData#state.streamid, D) of StateData#state.streamid, D) of
@ -447,15 +453,14 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
?INFO_MSG( ?INFO_MSG(
"(~w) Accepted legacy authentication for ~s", "(~w) Accepted legacy authentication for ~s",
[StateData#state.socket, [StateData#state.socket,
jlib:jid_to_string(JID)]), exmpp_jid:jid_to_string(JID)]),
SID = {now(), self()}, SID = {now(), self()},
Conn = get_conn_type(StateData), Conn = get_conn_type(StateData),
Info = [{ip, StateData#state.ip}, {conn, Conn}, Info = [{ip, StateData#state.ip}, {conn, Conn},
{auth_module, AuthModule}], {auth_module, AuthModule}],
ejabberd_sm:open_session( ejabberd_sm:open_session(
SID, U, StateData#state.server, R, Info), SID, U, StateData#state.server, R, Info),
Res1 = jlib:make_result_iq_reply(El), Res = exmpp_server_legacy_auth:success(El),
Res = setelement(4, Res1, []),
send_element(StateData, Res), send_element(StateData, Res),
change_shaper(StateData, JID), change_shaper(StateData, JID),
{Fs, Ts} = ejabberd_hooks:run_fold( {Fs, Ts} = ejabberd_hooks:run_fold(
@ -463,12 +468,10 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
StateData#state.server, StateData#state.server,
{[], []}, {[], []},
[U, StateData#state.server]), [U, StateData#state.server]),
LJID = jlib:jid_tolower( LJID = {JID#jid.lnode, JID#jid.ldomain, ""},
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, StateData#state.server, privacy_get_user_list, StateData#state.server,
#userlist{}, #userlist{},
[U, StateData#state.server]), [U, StateData#state.server]),
@ -487,31 +490,32 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
?INFO_MSG( ?INFO_MSG(
"(~w) Failed legacy authentication for ~s", "(~w) Failed legacy authentication for ~s",
[StateData#state.socket, [StateData#state.socket,
jlib:jid_to_string(JID)]), exmpp_jid:jid_to_string(JID)]),
Err = jlib:make_error_reply( Err = exmpp_stanza:error('not-authorized'),
El, ?ERR_NOT_AUTHORIZED), Res = exmpp_iq:error_without_original(El, Err),
send_element(StateData, Err), send_element(StateData, Res),
fsm_next_state(wait_for_auth, StateData) fsm_next_state(wait_for_auth, StateData)
end; end;
_ -> _ ->
if ?INFO_MSG(
JID == error -> "(~w) Forbidden legacy authentication for ~s",
[StateData#state.socket,
exmpp_jid:jid_to_string(JID)]),
Err = exmpp_stanza:error('not-allowed'),
Res = exmpp_iq:error_without_original(El, Err),
send_element(StateData, Res),
fsm_next_state(wait_for_auth, StateData)
end
catch
throw:_Exception ->
?INFO_MSG( ?INFO_MSG(
"(~w) Forbidden legacy authentication for " "(~w) Forbidden legacy authentication for "
"username '~s' with resource '~s'", "username '~s' with resource '~s'",
[StateData#state.socket, U, R]), [StateData#state.socket, U, R]),
Err = jlib:make_error_reply(El, ?ERR_JID_MALFORMED), Err1 = exmpp_stanza:error('jid-malformed'),
send_element(StateData, Err), Res1 = exmpp_iq:error_without_original(El, Err1),
fsm_next_state(wait_for_auth, StateData); send_element(StateData, Res1),
true ->
?INFO_MSG(
"(~w) Forbidden legacy authentication for ~s",
[StateData#state.socket,
jlib:jid_to_string(JID)]),
Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
send_element(StateData, Err),
fsm_next_state(wait_for_auth, StateData) fsm_next_state(wait_for_auth, StateData)
end
end; end;
_ -> _ ->
process_unauthenticated_stanza(StateData, El), process_unauthenticated_stanza(StateData, El),
@ -522,38 +526,36 @@ wait_for_auth(timeout, StateData) ->
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_auth({xmlstreamend, _Name}, StateData) -> wait_for_auth({xmlstreamend, _Name}, StateData) ->
send_text(StateData, ?STREAM_TRAILER), send_element(StateData, exmpp_stream:closing()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_auth({xmlstreamerror, _}, StateData) -> wait_for_auth({xmlstreamerror, _}, StateData) ->
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
send_element(StateData, exmpp_stream:closing()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_auth(closed, StateData) -> wait_for_auth(closed, StateData) ->
{stop, normal, StateData}. {stop, normal, StateData}.
wait_for_feature_request({xmlstreamelement, El}, StateData) -> wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El},
{xmlelement, Name, Attrs, Els} = El, StateData) ->
Zlib = StateData#state.zlib, Zlib = StateData#state.zlib,
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,
SockMod = (StateData#state.sockmod):get_sockmod(StateData#state.socket), SockMod = (StateData#state.sockmod):get_sockmod(StateData#state.socket),
case {xml:get_attr_s("xmlns", Attrs), Name} of case {NS, Name} of
{?NS_SASL, "auth"} when not ((SockMod == gen_tcp) and TLSRequired) -> {?NS_SASL, 'auth'} when not ((SockMod == gen_tcp) and TLSRequired) ->
Mech = xml:get_attr_s("mechanism", Attrs), {auth, Mech, ClientIn} = exmpp_server_sasl:next_step(El),
ClientIn = jlib:decode_base64(xml:get_cdata(Els)),
case cyrsasl:server_start(StateData#state.sasl_state, case cyrsasl:server_start(StateData#state.sasl_state,
Mech, Mech,
ClientIn) of ClientIn) of
{ok, Props} -> {ok, Props} ->
(StateData#state.sockmod):reset_stream( (StateData#state.sockmod):reset_stream(
StateData#state.socket), StateData#state.socket),
send_element(StateData, send_element(StateData, exmpp_server_sasl:success()),
{xmlelement, "success", U = proplists:get_value(username, Props),
[{"xmlns", ?NS_SASL}], []}),
U = xml:get_attr_s(username, Props),
?INFO_MSG("(~w) Accepted authentication for ~s", ?INFO_MSG("(~w) Accepted authentication for ~s",
[StateData#state.socket, U]), [StateData#state.socket, U]),
fsm_next_state(wait_for_stream, fsm_next_state(wait_for_stream,
@ -563,10 +565,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
user = U }); user = U });
{continue, ServerOut, NewSASLState} -> {continue, ServerOut, NewSASLState} ->
send_element(StateData, send_element(StateData,
{xmlelement, "challenge", exmpp_server_sasl:challenge(ServerOut)),
[{"xmlns", ?NS_SASL}],
[{xmlcdata,
jlib:encode_base64(ServerOut)}]}),
fsm_next_state(wait_for_sasl_response, fsm_next_state(wait_for_sasl_response,
StateData#state{ StateData#state{
sasl_state = NewSASLState}); sasl_state = NewSASLState});
@ -575,20 +574,18 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
"(~w) Failed authentication for ~s@~s", "(~w) Failed authentication for ~s@~s",
[StateData#state.socket, [StateData#state.socket,
Username, StateData#state.server]), Username, StateData#state.server]),
% XXX OLD FORMAT: list_to_atom(Error).
send_element(StateData, send_element(StateData,
{xmlelement, "failure", exmpp_server_sasl:failure(list_to_atom(Error))),
[{"xmlns", ?NS_SASL}],
[{xmlelement, Error, [], []}]}),
{next_state, wait_for_feature_request, StateData, {next_state, wait_for_feature_request, StateData,
?C2S_OPEN_TIMEOUT}; ?C2S_OPEN_TIMEOUT};
{error, Error} -> {error, Error} ->
% XXX OLD FORMAT: list_to_atom(Error).
send_element(StateData, send_element(StateData,
{xmlelement, "failure", exmpp_server_sasl:failure(list_to_atom(Error))),
[{"xmlns", ?NS_SASL}],
[{xmlelement, Error, [], []}]}),
fsm_next_state(wait_for_feature_request, StateData) fsm_next_state(wait_for_feature_request, StateData)
end; end;
{?NS_TLS, "starttls"} when TLS == true, {?NS_TLS, 'starttls'} when TLS == true,
TLSEnabled == false, TLSEnabled == false,
SockMod == gen_tcp -> SockMod == gen_tcp ->
TLSOpts = case ejabberd_config:get_local_option( TLSOpts = case ejabberd_config:get_local_option(
@ -601,55 +598,45 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
certfile, 1, StateData#state.tls_options)] certfile, 1, StateData#state.tls_options)]
end, end,
Socket = StateData#state.socket, Socket = StateData#state.socket,
Proceed = exmpp_xml:document_fragment_to_list(
exmpp_server_tls:proceed(), ?DEFAULT_NS, ?PREFIXED_NS),
TLSSocket = (StateData#state.sockmod):starttls( TLSSocket = (StateData#state.sockmod):starttls(
Socket, TLSOpts, Socket, TLSOpts,
xml:element_to_string( Proceed),
{xmlelement, "proceed", [{"xmlns", ?NS_TLS}], []})),
fsm_next_state(wait_for_stream, fsm_next_state(wait_for_stream,
StateData#state{socket = TLSSocket, StateData#state{socket = TLSSocket,
streamid = new_id(), streamid = new_id(),
tls_enabled = true tls_enabled = true
}); });
{?NS_COMPRESS, "compress"} when Zlib == true, {?NS_COMPRESS, 'compress'} when Zlib == true,
SockMod == gen_tcp -> SockMod == gen_tcp ->
case xml:get_subtag(El, "method") of case exmpp_server_compression:selected_method(El) of
false -> undefined ->
send_element(StateData, send_element(StateData,
{xmlelement, "failure", exmpp_server_compression:failure('steup-failed')),
[{"xmlns", ?NS_COMPRESS}],
[{xmlelement, "setup-failed", [], []}]}),
fsm_next_state(wait_for_feature_request, StateData); fsm_next_state(wait_for_feature_request, StateData);
Method ->
case xml:get_tag_cdata(Method) of
"zlib" -> "zlib" ->
Socket = StateData#state.socket, Socket = StateData#state.socket,
ZlibSocket = (StateData#state.sockmod):compress( ZlibSocket = (StateData#state.sockmod):compress(
Socket, Socket,
xml:element_to_string( exmpp_server_compression:compressed()),
{xmlelement, "compressed",
[{"xmlns", ?NS_COMPRESS}], []})),
fsm_next_state(wait_for_stream, fsm_next_state(wait_for_stream,
StateData#state{socket = ZlibSocket, StateData#state{socket = ZlibSocket,
streamid = new_id() streamid = new_id()
}); });
_ -> _ ->
send_element(StateData, send_element(StateData,
{xmlelement, "failure", exmpp_server_compression:failure('unsupported-method')),
[{"xmlns", ?NS_COMPRESS}],
[{xmlelement, "unsupported-method",
[], []}]}),
fsm_next_state(wait_for_feature_request, fsm_next_state(wait_for_feature_request,
StateData) StateData)
end
end; end;
_ -> _ ->
if if
(SockMod == gen_tcp) and TLSRequired -> (SockMod == gen_tcp) and TLSRequired ->
Lang = StateData#state.lang, Lang = StateData#state.lang,
send_text(StateData, ?POLICY_VIOLATION_ERR( send_element(StateData, exmpp_stream:error(
Lang, 'policy-violation', Lang, "Use of STARTTLS required")),
"Use of STARTTLS required") ++ send_element(StateData, exmpp_stream:closing()),
?STREAM_TRAILER),
{stop, normal, StateData}; {stop, normal, StateData};
true -> true ->
process_unauthenticated_stanza(StateData, El), process_unauthenticated_stanza(StateData, El),
@ -661,32 +648,31 @@ wait_for_feature_request(timeout, StateData) ->
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_feature_request({xmlstreamend, _Name}, StateData) -> wait_for_feature_request({xmlstreamend, _Name}, StateData) ->
send_text(StateData, ?STREAM_TRAILER), send_element(StateData, exmpp_stream:closing()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_feature_request({xmlstreamerror, _}, StateData) -> wait_for_feature_request({xmlstreamerror, _}, StateData) ->
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
send_element(StateData, exmpp_stream:closing()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_feature_request(closed, StateData) -> wait_for_feature_request(closed, StateData) ->
{stop, normal, StateData}. {stop, normal, StateData}.
wait_for_sasl_response({xmlstreamelement, El}, StateData) -> wait_for_sasl_response({xmlstreamelement, #xmlel{ns = NS, name = Name} = El},
{xmlelement, Name, Attrs, Els} = El, StateData) ->
case {xml:get_attr_s("xmlns", Attrs), Name} of case {NS, Name} of
{?NS_SASL, "response"} -> {?NS_SASL, 'response'} ->
ClientIn = jlib:decode_base64(xml:get_cdata(Els)), {response, ClientIn} = exmpp_server_sasl:next_step(El),
case cyrsasl:server_step(StateData#state.sasl_state, case cyrsasl:server_step(StateData#state.sasl_state,
ClientIn) of ClientIn) of
{ok, Props} -> {ok, Props} ->
(StateData#state.sockmod):reset_stream( (StateData#state.sockmod):reset_stream(
StateData#state.socket), StateData#state.socket),
send_element(StateData, send_element(StateData, exmpp_server_sasl:success()),
{xmlelement, "success", U = proplists:get_value(username, Props),
[{"xmlns", ?NS_SASL}], []}), AuthModule = proplists:get_value(auth_module, Props),
U = xml:get_attr_s(username, Props),
AuthModule = xml:get_attr_s(auth_module, Props),
?INFO_MSG("(~w) Accepted authentication for ~s", ?INFO_MSG("(~w) Accepted authentication for ~s",
[StateData#state.socket, U]), [StateData#state.socket, U]),
fsm_next_state(wait_for_stream, fsm_next_state(wait_for_stream,
@ -697,10 +683,7 @@ wait_for_sasl_response({xmlstreamelement, El}, StateData) ->
user = U}); user = U});
{continue, ServerOut, NewSASLState} -> {continue, ServerOut, NewSASLState} ->
send_element(StateData, send_element(StateData,
{xmlelement, "challenge", exmpp_server_sasl:challenge(ServerOut)),
[{"xmlns", ?NS_SASL}],
[{xmlcdata,
jlib:encode_base64(ServerOut)}]}),
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} ->
@ -708,16 +691,14 @@ wait_for_sasl_response({xmlstreamelement, El}, StateData) ->
"(~w) Failed authentication for ~s@~s", "(~w) Failed authentication for ~s@~s",
[StateData#state.socket, [StateData#state.socket,
Username, StateData#state.server]), Username, StateData#state.server]),
% XXX OLD FORMAT: list_to_atom(Error).
send_element(StateData, send_element(StateData,
{xmlelement, "failure", exmpp_server_sasl:failure(list_to_atom(Error))),
[{"xmlns", ?NS_SASL}],
[{xmlelement, Error, [], []}]}),
fsm_next_state(wait_for_feature_request, StateData); fsm_next_state(wait_for_feature_request, StateData);
{error, Error} -> {error, Error} ->
% XXX OLD FORMAT: list_to_atom(Error).
send_element(StateData, send_element(StateData,
{xmlelement, "failure", exmpp_server_sasl:failure(list_to_atom(Error))),
[{"xmlns", ?NS_SASL}],
[{xmlelement, Error, [], []}]}),
fsm_next_state(wait_for_feature_request, StateData) fsm_next_state(wait_for_feature_request, StateData)
end; end;
_ -> _ ->
@ -729,11 +710,12 @@ wait_for_sasl_response(timeout, StateData) ->
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_sasl_response({xmlstreamend, _Name}, StateData) -> wait_for_sasl_response({xmlstreamend, _Name}, StateData) ->
send_text(StateData, ?STREAM_TRAILER), send_element(StateData, exmpp_stream:closing()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_sasl_response({xmlstreamerror, _}, StateData) -> wait_for_sasl_response({xmlstreamerror, _}, StateData) ->
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
send_element(StateData, exmpp_stream:closing()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_sasl_response(closed, StateData) -> wait_for_sasl_response(closed, StateData) ->
@ -742,35 +724,25 @@ wait_for_sasl_response(closed, StateData) ->
wait_for_bind({xmlstreamelement, El}, StateData) -> wait_for_bind({xmlstreamelement, El}, StateData) ->
case jlib:iq_query_info(El) of try
#iq{type = set, xmlns = ?NS_BIND, sub_el = SubEl} = IQ ->
U = StateData#state.user, U = StateData#state.user,
R1 = xml:get_path_s(SubEl, [{elem, "resource"}, cdata]), R = case exmpp_server_binding:wished_resource(El) of
R = case jlib:resourceprep(R1) of undefined ->
error -> error; lists:concat([randoms:get_string() | tuple_to_list(now())]);
"" -> Resource ->
lists:concat( Resource
[randoms:get_string() | tuple_to_list(now())]);
Resource -> Resource
end, end,
case R of JID = exmpp_jid:make_jid(U, StateData#state.server, R),
error -> Res = exmpp_server_binding:bind(El, JID),
Err = jlib:make_error_reply(El, ?ERR_BAD_REQUEST), send_element(StateData, Res),
send_element(StateData, Err),
fsm_next_state(wait_for_bind, StateData);
_ ->
JID = jlib:make_jid(U, StateData#state.server, R),
Res = IQ#iq{type = result,
sub_el = [{xmlelement, "bind",
[{"xmlns", ?NS_BIND}],
[{xmlelement, "jid", [],
[{xmlcdata,
jlib:jid_to_string(JID)}]}]}]},
send_element(StateData, jlib:iq_to_xml(Res)),
fsm_next_state(wait_for_session, fsm_next_state(wait_for_session,
StateData#state{resource = R, jid = JID}) StateData#state{resource = R, jid = JID})
end; catch
_ -> throw:{stringprep, resourceprep, _, _} ->
Err = exmpp_server_binding:error(El, 'bad-request'),
send_element(StateData, Err),
fsm_next_state(wait_for_bind, StateData);
throw:Exception ->
fsm_next_state(wait_for_bind, StateData) fsm_next_state(wait_for_bind, StateData)
end; end;
@ -778,11 +750,12 @@ wait_for_bind(timeout, StateData) ->
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_bind({xmlstreamend, _Name}, StateData) -> wait_for_bind({xmlstreamend, _Name}, StateData) ->
send_text(StateData, ?STREAM_TRAILER), send_element(StateData, exmpp_stream:closing()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_bind({xmlstreamerror, _}, StateData) -> wait_for_bind({xmlstreamerror, _}, StateData) ->
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
send_element(StateData, exmpp_stream:closing()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_bind(closed, StateData) -> wait_for_bind(closed, StateData) ->
@ -791,24 +764,24 @@ wait_for_bind(closed, StateData) ->
wait_for_session({xmlstreamelement, El}, StateData) -> wait_for_session({xmlstreamelement, El}, StateData) ->
case jlib:iq_query_info(El) of try
#iq{type = set, xmlns = ?NS_SESSION} ->
U = StateData#state.user, U = StateData#state.user,
R = StateData#state.resource, R = StateData#state.resource,
JID = StateData#state.jid, JID = StateData#state.jid,
exmpp_server_session:want_establishment(El),
case acl:match_rule(StateData#state.server, case acl:match_rule(StateData#state.server,
StateData#state.access, JID) of StateData#state.access, JID) of
allow -> allow ->
?INFO_MSG("(~w) Opened session for ~s", ?INFO_MSG("(~w) Opened session for ~s",
[StateData#state.socket, [StateData#state.socket,
jlib:jid_to_string(JID)]), exmpp_jid:jid_to_string(JID)]),
SID = {now(), self()}, SID = {now(), self()},
Conn = get_conn_type(StateData), Conn = get_conn_type(StateData),
Info = [{ip, StateData#state.ip}, {conn, Conn}, Info = [{ip, StateData#state.ip}, {conn, Conn},
{auth_module, StateData#state.auth_module}], {auth_module, StateData#state.auth_module}],
ejabberd_sm:open_session( ejabberd_sm:open_session(
SID, U, StateData#state.server, R, Info), SID, U, StateData#state.server, R, Info),
Res = jlib:make_result_iq_reply(El), Res = exmpp_server_session:establish(El),
send_element(StateData, Res), send_element(StateData, Res),
change_shaper(StateData, JID), change_shaper(StateData, JID),
{Fs, Ts} = ejabberd_hooks:run_fold( {Fs, Ts} = ejabberd_hooks:run_fold(
@ -816,7 +789,7 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
StateData#state.server, StateData#state.server,
{[], []}, {[], []},
[U, StateData#state.server]), [U, StateData#state.server]),
LJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)), LJID = {JID#jid.lnode, JID#jid.ldomain, ""},
Fs1 = [LJID | Fs], Fs1 = [LJID | Fs],
Ts1 = [LJID | Ts], Ts1 = [LJID | Ts],
PrivList = PrivList =
@ -836,12 +809,13 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
StateData#state.server, [JID]), StateData#state.server, [JID]),
?INFO_MSG("(~w) Forbidden session for ~s", ?INFO_MSG("(~w) Forbidden session for ~s",
[StateData#state.socket, [StateData#state.socket,
jlib:jid_to_string(JID)]), exmpp_jid:jid_to_string(JID)]),
Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED), Err = exmpp_server_session:error(El, 'not-allowed'),
send_element(StateData, Err), send_element(StateData, Err),
fsm_next_state(wait_for_session, StateData) fsm_next_state(wait_for_session, StateData)
end; end
_ -> catch
throw:_Exception ->
fsm_next_state(wait_for_session, StateData) fsm_next_state(wait_for_session, StateData)
end; end;
@ -849,11 +823,12 @@ wait_for_session(timeout, StateData) ->
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_session({xmlstreamend, _Name}, StateData) -> wait_for_session({xmlstreamend, _Name}, StateData) ->
send_text(StateData, ?STREAM_TRAILER), send_element(StateData, exmpp_stream:closing()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_session({xmlstreamerror, _}, StateData) -> wait_for_session({xmlstreamerror, _}, StateData) ->
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
send_element(StateData, exmpp_stream:closing()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_session(closed, StateData) -> wait_for_session(closed, StateData) ->
@ -861,90 +836,121 @@ wait_for_session(closed, StateData) ->
session_established({xmlstreamelement, El}, StateData) -> session_established({xmlstreamelement, El}, StateData) ->
{xmlelement, Name, Attrs, _Els} = El, try
User = StateData#state.user, User = StateData#state.user,
Server = StateData#state.server, Server = StateData#state.server,
% TODO: check 'from' attribute in stanza % TODO: check 'from' attribute in stanza
FromJID = StateData#state.jid, FromJID = StateData#state.jid,
To = xml:get_attr_s("to", Attrs), To = exmpp_stanza:get_recipient(El),
ToJID = case To of ToJID = case To of
"" -> "" ->
jlib:make_jid(User, Server, ""); exmpp_jid:make_jid(User, Server, "");
_ -> _ ->
jlib:string_to_jid(To) exmpp_jid:string_to_jid(To)
end, end,
NewEl1 = jlib:remove_attr("xmlns", El), NewEl = case exmpp_stanza:get_lang(El) of
NewEl = case xml:get_attr_s("xml:lang", Attrs) of
"" -> "" ->
case StateData#state.lang of case StateData#state.lang of
"" -> NewEl1; "" -> El;
Lang -> Lang ->
xml:replace_tag_attr("xml:lang", Lang, NewEl1) exmpp_stanza:set_lang(El, Lang)
end; end;
_ -> _ ->
NewEl1 El
end, end,
NewState = NewState = case El of
case ToJID of #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence'} ->
error -> % XXX OLD FORMAT: NewEl.
case xml:get_attr_s("type", Attrs) of PresenceElOld = ejabberd_hooks:run_fold(
"error" -> StateData;
"result" -> StateData;
_ ->
Err = jlib:make_error_reply(NewEl, ?ERR_JID_MALFORMED),
send_element(StateData, Err),
StateData
end;
_ ->
case Name of
"presence" ->
PresenceEl = ejabberd_hooks:run_fold(
c2s_update_presence, c2s_update_presence,
Server, Server,
NewEl, exmpp_xml:xmlel_to_xmlelement(NewEl,
?DEFAULT_NS, ?PREFIXED_NS),
[User, Server]), [User, Server]),
PresenceEl = exmpp_xml:xmlelement_to_xmlel(PresenceElOld,
?DEFAULT_NS, ?PREFIXED_NS),
% XXX OLD FORMAT: PresenceElOld.
ejabberd_hooks:run( ejabberd_hooks:run(
user_send_packet, user_send_packet,
Server, Server,
[FromJID, ToJID, PresenceEl]), [FromJID, ToJID, PresenceElOld]),
case ToJID of case ToJID of
#jid{user = User, #jid{node = User,
server = Server, domain = Server,
resource = ""} -> resource = ""} ->
?DEBUG("presence_update(~p,~n\t~p,~n\t~p)", ?DEBUG("presence_update(~p,~n\t~p,~n\t~p)",
[FromJID, PresenceEl, StateData]), [FromJID, PresenceEl, StateData]),
presence_update(FromJID, PresenceEl, % XXX OLD FORMAT: PresenceElOld.
presence_update(FromJID, PresenceElOld,
StateData); StateData);
_ -> _ ->
presence_track(FromJID, ToJID, PresenceEl, % XXX OLD FORMAT: PresenceElOld.
presence_track(FromJID, ToJID, PresenceElOld,
StateData) StateData)
end; end;
"iq" -> #xmlel{ns = ?NS_JABBER_CLIENT, name = 'iq'} ->
case jlib:iq_query_info(NewEl) of IQ_Content = case exmpp_iq:get_type(El) of
#iq{xmlns = ?NS_PRIVACY} = IQ -> 'get' -> exmpp_iq:get_request(El);
'set' -> exmpp_iq:get_request(El);
'result' -> exmpp_iq:get_result(El);
'error' -> exmpp_stanza:get_error(El)
end,
case IQ_Content of
#xmlel{ns = ?NS_PRIVACY} = IQ ->
% XXX OLD FORMAT: IQ was #iq.
process_privacy_iq( process_privacy_iq(
FromJID, ToJID, IQ, StateData); FromJID, ToJID, IQ, StateData);
_ -> _ ->
% XXX OLD FORMAT: NewElOld.
NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl,
?DEFAULT_NS, ?PREFIXED_NS),
ejabberd_hooks:run( ejabberd_hooks:run(
user_send_packet, user_send_packet,
Server, Server,
[FromJID, ToJID, NewEl]), [FromJID, ToJID, NewElOld]),
% XXX OLD FORMAT: NewElOld.
ejabberd_router:route( ejabberd_router:route(
FromJID, ToJID, NewEl), FromJID, ToJID, NewElOld),
StateData StateData
end; end;
"message" -> #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message'} ->
% XXX OLD FORMAT: NewElOld.
NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl,
?DEFAULT_NS, ?PREFIXED_NS),
ejabberd_hooks:run(user_send_packet, ejabberd_hooks:run(user_send_packet,
Server, Server,
[FromJID, ToJID, NewEl]), [FromJID, ToJID, NewElOld]),
ejabberd_router:route(FromJID, ToJID, NewEl), % XXX OLD FORMAT: NewElOld.
ejabberd_router:route(FromJID, ToJID, NewElOld),
StateData; StateData;
_ -> _ ->
StateData StateData
end
end, end,
ejabberd_hooks:run(c2s_loop_debug, [{xmlstreamelement, El}]), % XXX OLD FORMAT: El.
fsm_next_state(session_established, NewState); ElOld = exmpp_xml:xmlel_to_xmlelement(El,
?DEFAULT_NS, ?PREFIXED_NS),
ejabberd_hooks:run(c2s_loop_debug, [{xmlstreamelement, ElOld}]),
fsm_next_state(session_established, NewState)
catch
throw:{stringprep, _, _, _} ->
case exmpp_stanza:get_type(El) of
"error" ->
ok;
"result" ->
ok;
_ ->
Err = exmpp_stanza:reply_with_error(El, 'jid-malformed'),
send_element(StateData, Err)
end,
% XXX OLD FORMAT: ElOld1.
ElOld1 = exmpp_xml:xmlel_to_xmlelement(El,
?DEFAULT_NS, ?PREFIXED_NS),
ejabberd_hooks:run(c2s_loop_debug, [{xmlstreamelement, ElOld1}]),
fsm_next_state(session_established, StateData);
throw:Exception ->
io:format("SESSION ESTABLISHED: Exception=~p~n", [Exception]),
fsm_next_state(session_established, StateData)
end;
%% We hibernate the process to reduce memory consumption after a %% We hibernate the process to reduce memory consumption after a
%% configurable activity timeout %% configurable activity timeout
@ -956,11 +962,12 @@ session_established(timeout, StateData) ->
fsm_next_state(session_established, StateData); fsm_next_state(session_established, StateData);
session_established({xmlstreamend, _Name}, StateData) -> session_established({xmlstreamend, _Name}, StateData) ->
send_text(StateData, ?STREAM_TRAILER), send_element(StateData, exmpp_stream:closing()),
{stop, normal, StateData}; {stop, normal, StateData};
session_established({xmlstreamerror, _}, StateData) -> session_established({xmlstreamerror, _}, StateData) ->
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
send_element(StateData, exmpp_stream:closing()),
{stop, normal, StateData}; {stop, normal, StateData};
session_established(closed, StateData) -> session_established(closed, StateData) ->