* src/ejabberd_s2s_in.erl: Changed timeout processing, bugfix

* src/ejabberd_s2s_out.erl: Changed timeout processing

* src/msgs/ru.msg: Updated (thanks to Sergei Golovan)

* src/mod_muc/mod_muc.erl: Better i18n support, added support for
<registered/> field in iq:register replies (thanks to Sergei
Golovan)

* src/mod_register.erl: More i18n support (thanks to Sergei
Golovan)

SVN Revision: 181
This commit is contained in:
Alexey Shchepin 2003-12-06 19:58:49 +00:00
parent 83a0be1009
commit 6f9a3922ef
6 changed files with 137 additions and 56 deletions

View File

@ -1,3 +1,18 @@
2003-12-06 Alexey Shchepin <alexey@sevcom.net>
* src/ejabberd_s2s_in.erl: Changed timeout processing, bugfix
* src/ejabberd_s2s_out.erl: Changed timeout processing
* src/msgs/ru.msg: Updated (thanks to Sergei Golovan)
* src/mod_muc/mod_muc.erl: Better i18n support, added support for
<registered/> field in iq:register replies (thanks to Sergei
Golovan)
* src/mod_register.erl: More i18n support (thanks to Sergei
Golovan)
2003-12-02 Alexey Shchepin <alexey@sevcom.net> 2003-12-02 Alexey Shchepin <alexey@sevcom.net>
* src/ejabberd_c2s.erl: Bugfix in processing of connection * src/ejabberd_c2s.erl: Bugfix in processing of connection

View File

@ -37,7 +37,8 @@
receiver, receiver,
streamid, streamid,
shaper, shaper,
connections = ?DICT:new()}). connections = ?DICT:new(),
timer}).
%-define(DBGFSM, true). %-define(DBGFSM, true).
@ -95,12 +96,13 @@ init([{SockMod, Socket}, Opts]) ->
{value, {_, S}} -> S; {value, {_, S}} -> S;
_ -> none _ -> none
end, end,
Timer = erlang:start_timer(?S2STIMEOUT, self(), []),
{ok, wait_for_stream, {ok, wait_for_stream,
#state{socket = Socket, #state{socket = Socket,
receiver = ReceiverPid, receiver = ReceiverPid,
streamid = new_id(), streamid = new_id(),
shaper = Shaper}, shaper = Shaper,
?S2STIMEOUT}. timer = Timer}}.
%%---------------------------------------------------------------------- %%----------------------------------------------------------------------
%% Func: StateName/2 %% Func: StateName/2
@ -114,7 +116,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
case {xml:get_attr_s("xmlns", Attrs), xml:get_attr_s("xmlns:db", Attrs)} of case {xml:get_attr_s("xmlns", Attrs), xml:get_attr_s("xmlns:db", Attrs)} of
{"jabber:server", "jabber:server:dialback"} -> {"jabber:server", "jabber:server:dialback"} ->
send_text(StateData#state.socket, ?STREAM_HEADER), send_text(StateData#state.socket, ?STREAM_HEADER),
{next_state, stream_established, StateData#state{}, ?S2STIMEOUT}; {next_state, stream_established, StateData#state{}};
_ -> _ ->
send_text(StateData#state.socket, ?INVALID_NAMESPACE_ERR), send_text(StateData#state.socket, ?INVALID_NAMESPACE_ERR),
{stop, normal, StateData} {stop, normal, StateData}
@ -132,6 +134,8 @@ wait_for_stream(closed, StateData) ->
{stop, normal, StateData}. {stop, normal, StateData}.
stream_established({xmlstreamelement, El}, StateData) -> stream_established({xmlstreamelement, El}, StateData) ->
cancel_timer(StateData#state.timer),
Timer = erlang:start_timer(?S2STIMEOUT, self(), []),
case is_key_packet(El) of case is_key_packet(El) of
{key, To, From, Id, Key} -> {key, To, From, Id, Key} ->
?INFO_MSG("GET KEY: ~p", [{To, From, Id, Key}]), ?INFO_MSG("GET KEY: ~p", [{To, From, Id, Key}]),
@ -147,8 +151,8 @@ stream_established({xmlstreamelement, El}, StateData) ->
change_shaper(StateData, jlib:make_jid("", LFrom, "")), change_shaper(StateData, jlib:make_jid("", LFrom, "")),
{next_state, {next_state,
stream_established, stream_established,
StateData#state{connections = Conns}, StateData#state{connections = Conns,
?S2STIMEOUT}; timer = Timer}};
_ -> _ ->
send_text(StateData#state.socket, ?HOST_UNKNOWN_ERR), send_text(StateData#state.socket, ?HOST_UNKNOWN_ERR),
{stop, normal, StateData} {stop, normal, StateData}
@ -169,7 +173,7 @@ stream_established({xmlstreamelement, El}, StateData) ->
{"id", Id}, {"id", Id},
{"type", Type}], {"type", Type}],
[]}), []}),
{next_state, wait_for_key, StateData, ?S2STIMEOUT}; {next_state, stream_established, StateData#state{timer = Timer}};
_ -> _ ->
{xmlelement, Name, Attrs, _Els} = El, {xmlelement, Name, Attrs, _Els} = El,
From_s = xml:get_attr_s("from", Attrs), From_s = xml:get_attr_s("from", Attrs),
@ -195,9 +199,9 @@ stream_established({xmlstreamelement, El}, StateData) ->
end; end;
true -> true ->
error error
end end,
end, {next_state, stream_established, StateData#state{timer = Timer}}
{next_state, stream_established, StateData, ?S2STIMEOUT}; end;
stream_established({valid, From, To}, StateData) -> stream_established({valid, From, To}, StateData) ->
send_element(StateData#state.socket, send_element(StateData#state.socket,
@ -212,7 +216,7 @@ stream_established({valid, From, To}, StateData) ->
NSD = StateData#state{ NSD = StateData#state{
connections = ?DICT:store({LFrom, LTo}, established, connections = ?DICT:store({LFrom, LTo}, established,
StateData#state.connections)}, StateData#state.connections)},
{next_state, stream_established, NSD, ?S2STIMEOUT}; {next_state, stream_established, NSD};
stream_established({invalid, From, To}, StateData) -> stream_established({invalid, From, To}, StateData) ->
send_element(StateData#state.socket, send_element(StateData#state.socket,
@ -225,9 +229,9 @@ stream_established({invalid, From, To}, StateData) ->
LFrom = jlib:nameprep(From), LFrom = jlib:nameprep(From),
LTo = jlib:nameprep(To), LTo = jlib:nameprep(To),
NSD = StateData#state{ NSD = StateData#state{
connections = ?DICT:store({LFrom, LTo}, established, connections = ?DICT:erase({LFrom, LTo},
StateData#state.connections)}, StateData#state.connections)},
{next_state, stream_established, NSD, ?S2STIMEOUT}; {next_state, stream_established, NSD};
stream_established({xmlstreamend, _Name}, StateData) -> stream_established({xmlstreamend, _Name}, StateData) ->
{stop, normal, StateData}; {stop, normal, StateData};
@ -265,7 +269,7 @@ stream_established(closed, StateData) ->
%% {stop, Reason, NewStateData} %% {stop, Reason, NewStateData}
%%---------------------------------------------------------------------- %%----------------------------------------------------------------------
handle_event(_Event, StateName, StateData) -> handle_event(_Event, StateName, StateData) ->
{next_state, StateName, StateData, ?S2STIMEOUT}. {next_state, StateName, StateData}.
%%---------------------------------------------------------------------- %%----------------------------------------------------------------------
%% Func: handle_sync_event/4 %% Func: handle_sync_event/4
@ -292,6 +296,11 @@ code_change(_OldVsn, StateName, StateData, _Extra) ->
handle_info({send_text, Text}, StateName, StateData) -> handle_info({send_text, Text}, StateName, StateData) ->
send_text(StateData#state.socket, Text), send_text(StateData#state.socket, Text),
{next_state, StateName, StateData}; {next_state, StateName, StateData};
handle_info({timeout, Timer, _}, StateName,
#state{timer = Timer} = StateData) ->
{stop, normal, StateData};
handle_info(_, StateName, StateData) -> handle_info(_, StateName, StateData) ->
{next_state, StateName, StateData}. {next_state, StateName, StateData}.
@ -333,6 +342,15 @@ change_shaper(StateData, JID) ->
new_id() -> new_id() ->
randoms:get_string(). randoms:get_string().
cancel_timer(Timer) ->
erlang:cancel_timer(Timer),
receive
{timeout, Timer, _} ->
ok
after 0 ->
ok
end.
is_key_packet({xmlelement, Name, Attrs, Els}) when Name == "db:result" -> is_key_packet({xmlelement, Name, Attrs, Els}) when Name == "db:result" ->
{key, {key,

View File

@ -32,7 +32,8 @@
-record(state, {socket, receiver, streamid, -record(state, {socket, receiver, streamid,
myname, server, xmlpid, queue, myname, server, xmlpid, queue,
new = false, verify = false}). new = false, verify = false,
timer}).
%-define(DBGFSM, true). %-define(DBGFSM, true).
@ -91,12 +92,13 @@ init([From, Server, Type]) ->
{verify, Pid, Key, SID} -> {verify, Pid, Key, SID} ->
{false, {Pid, Key, SID}} {false, {Pid, Key, SID}}
end, end,
Timer = erlang:start_timer(?S2STIMEOUT, self(), []),
{ok, open_socket, #state{queue = queue:new(), {ok, open_socket, #state{queue = queue:new(),
myname = From, myname = From,
server = Server, server = Server,
new = New, new = New,
verify = Verify}, verify = Verify,
?S2STIMEOUT}. timer = Timer}}.
%%---------------------------------------------------------------------- %%----------------------------------------------------------------------
%% Func: StateName/2 %% Func: StateName/2
@ -123,8 +125,7 @@ open_socket(init, StateData) ->
{next_state, wait_for_stream, {next_state, wait_for_stream,
StateData#state{socket = Socket, StateData#state{socket = Socket,
xmlpid = XMLStreamPid, xmlpid = XMLStreamPid,
streamid = new_id()}, streamid = new_id()}};
?S2STIMEOUT};
{error, Reason} -> {error, Reason} ->
?DEBUG("s2s_out: inet6 connect return ~p~n", [Reason]), ?DEBUG("s2s_out: inet6 connect return ~p~n", [Reason]),
Error = ?ERR_REMOTE_SERVER_NOT_FOUND, Error = ?ERR_REMOTE_SERVER_NOT_FOUND,
@ -174,8 +175,7 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
{"id", SID}], {"id", SID}],
[{xmlcdata, Key2}]}) [{xmlcdata, Key2}]})
end, end,
{next_state, wait_for_validation, {next_state, wait_for_validation, StateData#state{new = New}};
StateData#state{new = New}, ?S2STIMEOUT};
_ -> _ ->
send_text(StateData#state.socket, ?INVALID_NAMESPACE_ERR), send_text(StateData#state.socket, ?INVALID_NAMESPACE_ERR),
{stop, normal, StateData} {stop, normal, StateData}
@ -201,7 +201,7 @@ wait_for_validation({xmlstreamelement, El}, StateData) ->
case Type of case Type of
"valid" -> "valid" ->
send_queue(StateData#state.socket, StateData#state.queue), send_queue(StateData#state.socket, StateData#state.queue),
{next_state, stream_established, StateData, ?S2STIMEOUT}; {next_state, stream_established, StateData};
_ -> _ ->
% TODO: bounce packets % TODO: bounce packets
{stop, normal, StateData} {stop, normal, StateData}
@ -210,7 +210,7 @@ wait_for_validation({xmlstreamelement, El}, StateData) ->
?INFO_MSG("recv verify: ~p", [{From, To, Id, Type}]), ?INFO_MSG("recv verify: ~p", [{From, To, Id, Type}]),
case StateData#state.verify of case StateData#state.verify of
false -> false ->
{next_state, wait_for_validation, StateData, ?S2STIMEOUT}; {next_state, wait_for_validation, StateData};
{Pid, _Key, _SID} -> {Pid, _Key, _SID} ->
case Type of case Type of
"valid" -> "valid" ->
@ -227,7 +227,7 @@ wait_for_validation({xmlstreamelement, El}, StateData) ->
{stop, normal, StateData} {stop, normal, StateData}
end; end;
_ -> _ ->
{next_state, wait_for_validation, StateData, ?S2STIMEOUT} {next_state, wait_for_validation, StateData}
end; end;
wait_for_validation({xmlstreamend, Name}, StateData) -> wait_for_validation({xmlstreamend, Name}, StateData) ->
@ -270,7 +270,7 @@ stream_established({xmlstreamelement, El}, StateData) ->
_ -> _ ->
ok ok
end, end,
{next_state, stream_established, StateData, ?S2STIMEOUT}; {next_state, stream_established, StateData};
stream_established({xmlstreamend, Name}, StateData) -> stream_established({xmlstreamend, Name}, StateData) ->
{stop, normal, StateData}; {stop, normal, StateData};
@ -334,24 +334,40 @@ code_change(OldVsn, StateName, StateData, Extra) ->
%%---------------------------------------------------------------------- %%----------------------------------------------------------------------
handle_info({send_text, Text}, StateName, StateData) -> handle_info({send_text, Text}, StateName, StateData) ->
send_text(StateData#state.socket, Text), send_text(StateData#state.socket, Text),
{next_state, StateName, StateData}; cancel_timer(StateData#state.timer),
Timer = erlang:start_timer(?S2STIMEOUT, self(), []),
{next_state, StateName, StateData#state{timer = Timer}};
handle_info({send_element, El}, StateName, StateData) -> handle_info({send_element, El}, StateName, StateData) ->
cancel_timer(StateData#state.timer),
Timer = erlang:start_timer(?S2STIMEOUT, self(), []),
case StateName of case StateName of
stream_established -> stream_established ->
send_element(StateData#state.socket, El), send_element(StateData#state.socket, El),
{next_state, StateName, StateData}; {next_state, StateName, StateData#state{timer = Timer}};
_ -> _ ->
Q = queue:in(El, StateData#state.queue), Q = queue:in(El, StateData#state.queue),
{next_state, StateName, StateData#state{queue = Q}} {next_state, StateName, StateData#state{queue = Q,
timer = Timer}}
end; end;
handle_info({tcp, Socket, Data}, StateName, StateData) -> handle_info({tcp, Socket, Data}, StateName, StateData) ->
xml_stream:send_text(StateData#state.xmlpid, Data), xml_stream:send_text(StateData#state.xmlpid, Data),
{next_state, StateName, StateData}; {next_state, StateName, StateData};
handle_info({tcp_closed, Socket}, StateName, StateData) -> handle_info({tcp_closed, Socket}, StateName, StateData) ->
gen_fsm:send_event(self(), closed), gen_fsm:send_event(self(), closed),
{next_state, StateName, StateData}; {next_state, StateName, StateData};
handle_info({tcp_error, Socket, Reason}, StateName, StateData) -> handle_info({tcp_error, Socket, Reason}, StateName, StateData) ->
gen_fsm:send_event(self(), closed), gen_fsm:send_event(self(), closed),
{next_state, StateName, StateData};
handle_info({timeout, Timer, _}, StateName,
#state{timer = Timer} = StateData) ->
{stop, normal, StateData};
handle_info(_, StateName, StateData) ->
{next_state, StateName, StateData}. {next_state, StateName, StateData}.
%%---------------------------------------------------------------------- %%----------------------------------------------------------------------
@ -361,6 +377,8 @@ handle_info({tcp_error, Socket, Reason}, StateName, StateData) ->
%%---------------------------------------------------------------------- %%----------------------------------------------------------------------
terminate(Reason, StateName, StateData) -> terminate(Reason, StateName, StateData) ->
?INFO_MSG("terminated: ~p", [Reason]), ?INFO_MSG("terminated: ~p", [Reason]),
Error = ?ERR_REMOTE_SERVER_NOT_FOUND,
bounce_queue(StateData#state.queue, Error),
case StateData#state.new of case StateData#state.new of
false -> false ->
ok; ok;
@ -396,13 +414,34 @@ send_queue(Socket, Q) ->
ok ok
end. end.
bounce_queue(Q, Error) ->
case queue:out(Q) of
{{value, El}, Q1} ->
Err = jlib:make_error_reply(El, Error),
From = jlib:string_to_jid(xml:get_tag_attr_s("from", El)),
To = jlib:string_to_jid(xml:get_tag_attr_s("to", El)),
ejabberd_router:route(To, From, Err),
bounce_queue(Q1, Error);
{empty, Q1} ->
ok
end.
new_id() -> new_id() ->
randoms:get_string(). randoms:get_string().
cancel_timer(Timer) ->
erlang:cancel_timer(Timer),
receive
{timeout, Timer, _} ->
ok
after 0 ->
ok
end.
bounce_messages(Error) -> bounce_messages(Error) ->
receive receive
{send_element, El} -> {send_element, El} ->
{xmlelement, Name, Attrs, SubTags} = El, {xmlelement, _Name, Attrs, _SubTags} = El,
case xml:get_attr_s("type", Attrs) of case xml:get_attr_s("type", Attrs) of
"error" -> "error" ->
ok; ok;
@ -410,7 +449,7 @@ bounce_messages(Error) ->
Err = jlib:make_error_reply(El, Error), Err = jlib:make_error_reply(El, Error),
From = jlib:string_to_jid(xml:get_attr_s("from", Attrs)), From = jlib:string_to_jid(xml:get_attr_s("from", Attrs)),
To = jlib:string_to_jid(xml:get_attr_s("to", Attrs)), To = jlib:string_to_jid(xml:get_attr_s("to", Attrs)),
ejabberd_router ! {route, To, From, Err} ejabberd_router:route(To, From, Err)
end, end,
bounce_messages(Error) bounce_messages(Error)
after 0 -> after 0 ->

View File

@ -298,28 +298,30 @@ iq_disco_items(Host, From) ->
iq_get_register_info(From, Lang) -> iq_get_register_info(From, Lang) ->
{LUser, LServer, _} = jlib:jid_tolower(From), {LUser, LServer, _} = jlib:jid_tolower(From),
LUS = {LUser, LServer}, LUS = {LUser, LServer},
Nick = case catch mnesia:dirty_read(muc_registered, LUS) of {Nick, Registered} = case catch mnesia:dirty_read(muc_registered, LUS) of
{'EXIT', Reason} -> {'EXIT', Reason} ->
""; {"", []};
[] -> [] ->
""; {"", []};
[#muc_registered{nick = N}] -> [#muc_registered{nick = N}] ->
N {N, [{xmlelement, "registered", [], []}]}
end, end,
[{xmlelement, "instructions", [], Registered ++
[{xmlcdata, translate:translate( [{xmlelement, "instructions", [],
Lang, "You need a x:data capable client to register.")}]}, [{xmlcdata,
{xmlelement, "x", translate:translate(
[{"xmlns", ?NS_XDATA}], Lang, "You need a x:data capable client to register.")}]},
[{xmlelement, "title", [], {xmlelement, "x",
[{xmlcdata, [{"xmlns", ?NS_XDATA}],
translate:translate( [{xmlelement, "title", [],
Lang, "Nick Registration")}]}, [{xmlcdata,
{xmlelement, "instructions", [], translate:translate(
[{xmlcdata, Lang, "Nickname Registration")}]},
translate:translate( {xmlelement, "instructions", [],
Lang, "Enter nick you want to register.")}]}, [{xmlcdata,
?XFIELD("text-single", "Nick", "nick", Nick)]}]. translate:translate(
Lang, "Enter nickname you want to register.")}]},
?XFIELD("text-single", "Nickname", "nick", Nick)]}].
iq_set_register_info(From, XData) -> iq_set_register_info(From, XData) ->
{LUser, LServer, _} = jlib:jid_tolower(From), {LUser, LServer, _} = jlib:jid_tolower(From),
@ -358,7 +360,7 @@ iq_set_register_info(From, XData) ->
{atomic, ok} -> {atomic, ok} ->
{result, []}; {result, []};
{atomic, false} -> {atomic, false} ->
{error, ?ERR_NOT_ALLOWED}; {error, ?ERR_CONFLICT};
_ -> _ ->
{error, ?ERR_INTERNAL_SERVER_ERROR} {error, ?ERR_INTERNAL_SERVER_ERROR}
end end
@ -394,8 +396,8 @@ iq_get_vcard(Lang) ->
[{xmlcdata, [{xmlcdata,
"http://ejabberd.jabberstudio.org/"}]}, "http://ejabberd.jabberstudio.org/"}]},
{xmlelement, "DESC", [], {xmlelement, "DESC", [],
[{xmlcdata, "ejabberd MUC module\n" [{xmlcdata, translate:translate(Lang, "ejabberd MUC module\n"
"Copyright (c) 2003 Alexey Shchepin"}]}]. "Copyright (c) 2003 Alexey Shchepin")}]}].
broadcast_service_message(Msg) -> broadcast_service_message(Msg) ->

View File

@ -99,13 +99,15 @@ process_iq(From, _To, {iq, ID, Type, XMLNS, SubEl}) ->
[SubEl, ?ERR_BAD_REQUEST]} [SubEl, ?ERR_BAD_REQUEST]}
end; end;
get -> get ->
Lang = xml:get_tag_attr_s("xml:lang", SubEl),
{iq, ID, result, XMLNS, [{xmlelement, {iq, ID, result, XMLNS, [{xmlelement,
"query", "query",
[{"xmlns", "jabber:iq:register"}], [{"xmlns", "jabber:iq:register"}],
[{xmlelement, "instructions", [], [{xmlelement, "instructions", [],
[{xmlcdata, [{xmlcdata,
"Choose a username and password " translate:translate(Lang,
"to register with this server."}]}, "Choose a username and password "
"to register with this server.")}]},
{xmlelement, "username", [], []}, {xmlelement, "username", [], []},
{xmlelement, "password", [], []}]}]} {xmlelement, "password", [], []}]}]}
end. end.

View File

@ -38,8 +38,9 @@
{"Start Modules", "Запуск модулей"}. {"Start Modules", "Запуск модулей"}.
{"Stop Modules", "Остановка модулей"}. {"Stop Modules", "Остановка модулей"}.
% mod_register.erl
{"Choose a username and password to register with this server.",
"Выберите идентификатор пользователя и пароль для регистрации на этом сервере."}.
% mod_vcard.erl % mod_vcard.erl
{"You need a x:data capable client to search", {"You need a x:data capable client to search",
@ -62,9 +63,13 @@
{"Organization Name", "Название организации"}. {"Organization Name", "Название организации"}.
{"Organization Unit", "Отдел организации"}. {"Organization Unit", "Отдел организации"}.
% mod_muc/mod_muc.erl
{"Nickname Registration", "Регистрация псевдонима"}.
{"Enter nickname you want to register.", "Введите псевдоним, который вы хотели бы зарегистрировать"}.
{"ejabberd MUC module\nCopyright (c) 2003 Alexey Shchepin",
"ejabberd MUC модуль\nCopyright (c) 2003 Алексей Щепин"}.
% mod_muc/mod_muc_room.erl % mod_muc/mod_muc_room.erl
{"Room title", "Название комнаты"}. {"Room title", "Название комнаты"}.
{"Allow users to change subject?", "Разрешить пользователям изменять тему?"}. {"Allow users to change subject?", "Разрешить пользователям изменять тему?"}.
{"Allow users to query other users?", {"Allow users to query other users?",