diff --git a/ChangeLog b/ChangeLog index f313d3ea0..5ed445ea7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2003-12-06 Alexey Shchepin + + * 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 + 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 * src/ejabberd_c2s.erl: Bugfix in processing of connection diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 7c52dc025..4da98478e 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -37,7 +37,8 @@ receiver, streamid, shaper, - connections = ?DICT:new()}). + connections = ?DICT:new(), + timer}). %-define(DBGFSM, true). @@ -95,12 +96,13 @@ init([{SockMod, Socket}, Opts]) -> {value, {_, S}} -> S; _ -> none end, + Timer = erlang:start_timer(?S2STIMEOUT, self(), []), {ok, wait_for_stream, #state{socket = Socket, receiver = ReceiverPid, streamid = new_id(), - shaper = Shaper}, - ?S2STIMEOUT}. + shaper = Shaper, + timer = Timer}}. %%---------------------------------------------------------------------- %% 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 {"jabber:server", "jabber:server:dialback"} -> 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), {stop, normal, StateData} @@ -132,6 +134,8 @@ wait_for_stream(closed, StateData) -> {stop, normal, StateData}. stream_established({xmlstreamelement, El}, StateData) -> + cancel_timer(StateData#state.timer), + Timer = erlang:start_timer(?S2STIMEOUT, self(), []), case is_key_packet(El) of {key, 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, "")), {next_state, stream_established, - StateData#state{connections = Conns}, - ?S2STIMEOUT}; + StateData#state{connections = Conns, + timer = Timer}}; _ -> send_text(StateData#state.socket, ?HOST_UNKNOWN_ERR), {stop, normal, StateData} @@ -169,7 +173,7 @@ stream_established({xmlstreamelement, El}, StateData) -> {"id", Id}, {"type", Type}], []}), - {next_state, wait_for_key, StateData, ?S2STIMEOUT}; + {next_state, stream_established, StateData#state{timer = Timer}}; _ -> {xmlelement, Name, Attrs, _Els} = El, From_s = xml:get_attr_s("from", Attrs), @@ -195,9 +199,9 @@ stream_established({xmlstreamelement, El}, StateData) -> end; true -> error - end - end, - {next_state, stream_established, StateData, ?S2STIMEOUT}; + end, + {next_state, stream_established, StateData#state{timer = Timer}} + end; stream_established({valid, From, To}, StateData) -> send_element(StateData#state.socket, @@ -212,7 +216,7 @@ stream_established({valid, From, To}, StateData) -> NSD = StateData#state{ connections = ?DICT:store({LFrom, LTo}, established, StateData#state.connections)}, - {next_state, stream_established, NSD, ?S2STIMEOUT}; + {next_state, stream_established, NSD}; stream_established({invalid, From, To}, StateData) -> send_element(StateData#state.socket, @@ -225,9 +229,9 @@ stream_established({invalid, From, To}, StateData) -> LFrom = jlib:nameprep(From), LTo = jlib:nameprep(To), NSD = StateData#state{ - connections = ?DICT:store({LFrom, LTo}, established, + connections = ?DICT:erase({LFrom, LTo}, StateData#state.connections)}, - {next_state, stream_established, NSD, ?S2STIMEOUT}; + {next_state, stream_established, NSD}; stream_established({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; @@ -265,7 +269,7 @@ stream_established(closed, StateData) -> %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- handle_event(_Event, StateName, StateData) -> - {next_state, StateName, StateData, ?S2STIMEOUT}. + {next_state, StateName, StateData}. %%---------------------------------------------------------------------- %% Func: handle_sync_event/4 @@ -292,6 +296,11 @@ code_change(_OldVsn, StateName, StateData, _Extra) -> handle_info({send_text, Text}, StateName, StateData) -> send_text(StateData#state.socket, Text), {next_state, StateName, StateData}; + +handle_info({timeout, Timer, _}, StateName, + #state{timer = Timer} = StateData) -> + {stop, normal, StateData}; + handle_info(_, StateName, StateData) -> {next_state, StateName, StateData}. @@ -333,6 +342,15 @@ change_shaper(StateData, JID) -> new_id() -> 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" -> {key, diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index da2c93c50..8e4394d6b 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -32,7 +32,8 @@ -record(state, {socket, receiver, streamid, myname, server, xmlpid, queue, - new = false, verify = false}). + new = false, verify = false, + timer}). %-define(DBGFSM, true). @@ -91,12 +92,13 @@ init([From, Server, Type]) -> {verify, Pid, Key, SID} -> {false, {Pid, Key, SID}} end, + Timer = erlang:start_timer(?S2STIMEOUT, self(), []), {ok, open_socket, #state{queue = queue:new(), myname = From, server = Server, new = New, - verify = Verify}, - ?S2STIMEOUT}. + verify = Verify, + timer = Timer}}. %%---------------------------------------------------------------------- %% Func: StateName/2 @@ -123,8 +125,7 @@ open_socket(init, StateData) -> {next_state, wait_for_stream, StateData#state{socket = Socket, xmlpid = XMLStreamPid, - streamid = new_id()}, - ?S2STIMEOUT}; + streamid = new_id()}}; {error, Reason} -> ?DEBUG("s2s_out: inet6 connect return ~p~n", [Reason]), Error = ?ERR_REMOTE_SERVER_NOT_FOUND, @@ -174,8 +175,7 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> {"id", SID}], [{xmlcdata, Key2}]}) end, - {next_state, wait_for_validation, - StateData#state{new = New}, ?S2STIMEOUT}; + {next_state, wait_for_validation, StateData#state{new = New}}; _ -> send_text(StateData#state.socket, ?INVALID_NAMESPACE_ERR), {stop, normal, StateData} @@ -201,7 +201,7 @@ wait_for_validation({xmlstreamelement, El}, StateData) -> case Type of "valid" -> send_queue(StateData#state.socket, StateData#state.queue), - {next_state, stream_established, StateData, ?S2STIMEOUT}; + {next_state, stream_established, StateData}; _ -> % TODO: bounce packets {stop, normal, StateData} @@ -210,7 +210,7 @@ wait_for_validation({xmlstreamelement, El}, StateData) -> ?INFO_MSG("recv verify: ~p", [{From, To, Id, Type}]), case StateData#state.verify of false -> - {next_state, wait_for_validation, StateData, ?S2STIMEOUT}; + {next_state, wait_for_validation, StateData}; {Pid, _Key, _SID} -> case Type of "valid" -> @@ -227,7 +227,7 @@ wait_for_validation({xmlstreamelement, El}, StateData) -> {stop, normal, StateData} end; _ -> - {next_state, wait_for_validation, StateData, ?S2STIMEOUT} + {next_state, wait_for_validation, StateData} end; wait_for_validation({xmlstreamend, Name}, StateData) -> @@ -270,7 +270,7 @@ stream_established({xmlstreamelement, El}, StateData) -> _ -> ok end, - {next_state, stream_established, StateData, ?S2STIMEOUT}; + {next_state, stream_established, StateData}; stream_established({xmlstreamend, Name}, StateData) -> {stop, normal, StateData}; @@ -334,24 +334,40 @@ code_change(OldVsn, StateName, StateData, Extra) -> %%---------------------------------------------------------------------- handle_info({send_text, Text}, StateName, StateData) -> 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) -> + cancel_timer(StateData#state.timer), + Timer = erlang:start_timer(?S2STIMEOUT, self(), []), case StateName of stream_established -> send_element(StateData#state.socket, El), - {next_state, StateName, StateData}; + {next_state, StateName, StateData#state{timer = Timer}}; _ -> Q = queue:in(El, StateData#state.queue), - {next_state, StateName, StateData#state{queue = Q}} + {next_state, StateName, StateData#state{queue = Q, + timer = Timer}} end; + handle_info({tcp, Socket, Data}, StateName, StateData) -> xml_stream:send_text(StateData#state.xmlpid, Data), {next_state, StateName, StateData}; + handle_info({tcp_closed, Socket}, StateName, StateData) -> gen_fsm:send_event(self(), closed), {next_state, StateName, StateData}; + handle_info({tcp_error, Socket, Reason}, StateName, StateData) -> 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}. %%---------------------------------------------------------------------- @@ -361,6 +377,8 @@ handle_info({tcp_error, Socket, Reason}, StateName, StateData) -> %%---------------------------------------------------------------------- terminate(Reason, StateName, StateData) -> ?INFO_MSG("terminated: ~p", [Reason]), + Error = ?ERR_REMOTE_SERVER_NOT_FOUND, + bounce_queue(StateData#state.queue, Error), case StateData#state.new of false -> ok; @@ -396,13 +414,34 @@ send_queue(Socket, Q) -> ok 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() -> randoms:get_string(). +cancel_timer(Timer) -> + erlang:cancel_timer(Timer), + receive + {timeout, Timer, _} -> + ok + after 0 -> + ok + end. + bounce_messages(Error) -> receive {send_element, El} -> - {xmlelement, Name, Attrs, SubTags} = El, + {xmlelement, _Name, Attrs, _SubTags} = El, case xml:get_attr_s("type", Attrs) of "error" -> ok; @@ -410,7 +449,7 @@ bounce_messages(Error) -> Err = jlib:make_error_reply(El, Error), From = jlib:string_to_jid(xml:get_attr_s("from", 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, bounce_messages(Error) after 0 -> diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index ce1328ca6..7f1c5360c 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -298,28 +298,30 @@ iq_disco_items(Host, From) -> iq_get_register_info(From, Lang) -> {LUser, LServer, _} = jlib:jid_tolower(From), 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} -> - ""; + {"", []}; [] -> - ""; + {"", []}; [#muc_registered{nick = N}] -> - N + {N, [{xmlelement, "registered", [], []}]} end, - [{xmlelement, "instructions", [], - [{xmlcdata, translate:translate( - Lang, "You need a x:data capable client to register.")}]}, - {xmlelement, "x", - [{"xmlns", ?NS_XDATA}], - [{xmlelement, "title", [], - [{xmlcdata, - translate:translate( - Lang, "Nick Registration")}]}, - {xmlelement, "instructions", [], - [{xmlcdata, - translate:translate( - Lang, "Enter nick you want to register.")}]}, - ?XFIELD("text-single", "Nick", "nick", Nick)]}]. + Registered ++ + [{xmlelement, "instructions", [], + [{xmlcdata, + translate:translate( + Lang, "You need a x:data capable client to register.")}]}, + {xmlelement, "x", + [{"xmlns", ?NS_XDATA}], + [{xmlelement, "title", [], + [{xmlcdata, + translate:translate( + Lang, "Nickname Registration")}]}, + {xmlelement, "instructions", [], + [{xmlcdata, + translate:translate( + Lang, "Enter nickname you want to register.")}]}, + ?XFIELD("text-single", "Nickname", "nick", Nick)]}]. iq_set_register_info(From, XData) -> {LUser, LServer, _} = jlib:jid_tolower(From), @@ -358,7 +360,7 @@ iq_set_register_info(From, XData) -> {atomic, ok} -> {result, []}; {atomic, false} -> - {error, ?ERR_NOT_ALLOWED}; + {error, ?ERR_CONFLICT}; _ -> {error, ?ERR_INTERNAL_SERVER_ERROR} end @@ -394,8 +396,8 @@ iq_get_vcard(Lang) -> [{xmlcdata, "http://ejabberd.jabberstudio.org/"}]}, {xmlelement, "DESC", [], - [{xmlcdata, "ejabberd MUC module\n" - "Copyright (c) 2003 Alexey Shchepin"}]}]. + [{xmlcdata, translate:translate(Lang, "ejabberd MUC module\n" + "Copyright (c) 2003 Alexey Shchepin")}]}]. broadcast_service_message(Msg) -> diff --git a/src/mod_register.erl b/src/mod_register.erl index 52ebcb00f..f900a9ef0 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -99,13 +99,15 @@ process_iq(From, _To, {iq, ID, Type, XMLNS, SubEl}) -> [SubEl, ?ERR_BAD_REQUEST]} end; get -> + Lang = xml:get_tag_attr_s("xml:lang", SubEl), {iq, ID, result, XMLNS, [{xmlelement, "query", [{"xmlns", "jabber:iq:register"}], [{xmlelement, "instructions", [], [{xmlcdata, - "Choose a username and password " - "to register with this server."}]}, + translate:translate(Lang, + "Choose a username and password " + "to register with this server.")}]}, {xmlelement, "username", [], []}, {xmlelement, "password", [], []}]}]} end. diff --git a/src/msgs/ru.msg b/src/msgs/ru.msg index c9bb60c45..782b6acd2 100644 --- a/src/msgs/ru.msg +++ b/src/msgs/ru.msg @@ -38,8 +38,9 @@ {"Start Modules", "Запуск модулей"}. {"Stop Modules", "Остановка модулей"}. - - +% mod_register.erl +{"Choose a username and password to register with this server.", + "Выберите идентификатор пользователя и пароль для регистрации на этом сервере."}. % mod_vcard.erl {"You need a x:data capable client to search", @@ -62,9 +63,13 @@ {"Organization Name", "Название организации"}. {"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 - {"Room title", "Название комнаты"}. {"Allow users to change subject?", "Разрешить пользователям изменять тему?"}. {"Allow users to query other users?",